/*
 * FreeRTOS Kernel V10.4.3
 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * https://www.FreeRTOS.org
 * https://github.com/FreeRTOS
 *
 */

/* Standard includes. */
#include <stdlib.h>
#include <string.h>

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "stack_macros.h"

/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting
 * functions but without including stdio.h here. */
#if (configUSE_STATS_FORMATTING_FUNCTIONS == 1)

/* At the bottom of this file are two optional functions that can be used
 * to generate human readable text from the raw data generated by the
 * uxTaskGetSystemState() function.  Note the formatting functions are provided
 * for convenience only, and are NOT considered part of the kernel. */
#include <stdio.h>
#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */

//configUSE_PREEMPTION = 1
#define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()

/* Values that can be assigned to the ucNotifyState member of the TCB. */
#define taskNOT_WAITING_NOTIFICATION ((uint8_t)0) /* Must be zero as it is the initialised value. */
#define taskWAITING_NOTIFICATION ((uint8_t)1)
#define taskNOTIFICATION_RECEIVED ((uint8_t)2)

/*
 * 初始化任务栈时，在栈中填充的内容，可用于辅助计算watermark
 */
#define tskSTACK_FILL_BYTE (0xa5U)

/* 标记任务的TCB和栈是何种内存分配方式. */
#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ((uint8_t)0)
#define tskSTATICALLY_ALLOCATED_STACK_ONLY ((uint8_t)1)
#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ((uint8_t)2)

/* If any of the following are set then task stacks are filled with a known
 * value so the high water mark can be determined.  If none of the following are
 * set then don't fill the stack so there is no unnecessary dependency on memset. */
#if ((configCHECK_FOR_STACK_OVERFLOW > 1) || (configUSE_TRACE_FACILITY == 1) || (INCLUDE_uxTaskGetStackHighWaterMark == 1) || (INCLUDE_uxTaskGetStackHighWaterMark2 == 1))
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 1
#else
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 0
#endif

/*
 * Macros used by vListTask to indicate which state a task is in.
 */
#define tskRUNNING_CHAR ('X')
#define tskBLOCKED_CHAR ('B')
#define tskREADY_CHAR ('R')
#define tskDELETED_CHAR ('D')
#define tskSUSPENDED_CHAR ('S')

/*
 * Some kernel aware debuggers require the data the debugger needs access to be
 * global, rather than file scope.
 */
#ifdef portREMOVE_STATIC_QUALIFIER
#define static
#endif

/* The name allocated to the Idle task.  This can be overridden by defining
 * configIDLE_TASK_NAME in FreeRTOSConfig.h. */
#ifndef configIDLE_TASK_NAME
#define configIDLE_TASK_NAME "IDLE"
#endif

/* configUSE_PORT_OPTIMISED_TASK_SELECTION==0 使用通用的任务选择策略 */
#if (configUSE_PORT_OPTIMISED_TASK_SELECTION == 0)

/* uxTopReadyPriority 保存就绪任务的最高优先级，该宏更新uxTopReadyPriority */
#define taskRECORD_READY_PRIORITY(uxPriority)  \
    {                                          \
        if ((uxPriority) > uxTopReadyPriority) \
        {                                      \
            uxTopReadyPriority = (uxPriority); \
        }                                      \
    } /* taskRECORD_READY_PRIORITY */

/*-----------------------------------------------------------*/

//任务选择：选择就绪链表中，优先级最高的第一个任务
#define taskSELECT_HIGHEST_PRIORITY_TASK()                                              \
    {                                                                                   \
        UBaseType_t uxTopPriority = uxTopReadyPriority;                                 \
                                                                                        \
        /* 找出就绪链表数组中，优先级最高的链表 */                    \
        while (listLIST_IS_EMPTY(&(pxReadyTasksLists[uxTopPriority])))                  \
        {                                                                               \
            configASSERT(uxTopPriority);                                                \
            --uxTopPriority;                                                            \
        }                                                                               \
                                                                                        \
        /* 获取就绪链表第一个任务到pxCurrentTCB 记录uxTopReadyPriority */                 \
        listGET_OWNER_OF_NEXT_ENTRY(pxCurrentTCB, &(pxReadyTasksLists[uxTopPriority])); \
        uxTopReadyPriority = uxTopPriority;                                             \
    }
/* taskSELECT_HIGHEST_PRIORITY_TASK */

/*-----------------------------------------------------------*/

//使用通用的任务选择时、这些宏没有意义
#define taskRESET_READY_PRIORITY(uxPriority)
#define portRESET_READY_PRIORITY(uxPriority, uxTopReadyPriority)

#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

/* 任务选择策略与具体的硬件架构相关 */

/* 由硬件提供taskRECORD_READY_PRIORITY的实现，更新uxTopReadyPriority*/
#define taskRECORD_READY_PRIORITY(uxPriority) portRECORD_READY_PRIORITY(uxPriority, uxTopReadyPriority)

/*-----------------------------------------------------------*/

#define taskSELECT_HIGHEST_PRIORITY_TASK()                                              \
    {                                                                                   \
        UBaseType_t uxTopPriority;                                                      \
                                                                                        \
        /* Find the highest priority list that contains ready tasks. */                 \
        portGET_HIGHEST_PRIORITY(uxTopPriority, uxTopReadyPriority);                    \
        configASSERT(listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[uxTopPriority])) > 0); \
        listGET_OWNER_OF_NEXT_ENTRY(pxCurrentTCB, &(pxReadyTasksLists[uxTopPriority])); \
    } /* taskSELECT_HIGHEST_PRIORITY_TASK() */

/*-----------------------------------------------------------*/

//重置uxTopReadyPriority
#define taskRESET_READY_PRIORITY(uxPriority)                                               \
    {                                                                                      \
        if (listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[(uxPriority)])) == (UBaseType_t)0) \
        {                                                                                  \
            portRESET_READY_PRIORITY((uxPriority), (uxTopReadyPriority));                  \
        }                                                                                  \
    }

#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

/*-----------------------------------------------------------*/

//当时钟溢出时，切换两个延时链表
#define taskSWITCH_DELAYED_LISTS()                                                \
    {                                                                             \
        List_t *pxTemp;                                                           \
                                                                                  \
        /* The delayed tasks list should be empty when the lists are switched. */ \
        configASSERT((listLIST_IS_EMPTY(pxDelayedTaskList)));                     \
                                                                                  \
        pxTemp = pxDelayedTaskList;                                               \
        pxDelayedTaskList = pxOverflowDelayedTaskList;                            \
        pxOverflowDelayedTaskList = pxTemp;                                       \
        xNumOfOverflows++;                                                        \
        prvResetNextTaskUnblockTime();                                            \
    }

/*-----------------------------------------------------------*/

//将任务插入到对应的就绪链表尾
#define prvAddTaskToReadyList(pxTCB)                                                       \
    traceMOVED_TASK_TO_READY_STATE(pxTCB);                                                 \
    taskRECORD_READY_PRIORITY((pxTCB)->uxPriority);                                        \
    vListInsertEnd(&(pxReadyTasksLists[(pxTCB)->uxPriority]), &((pxTCB)->xStateListItem)); \
    tracePOST_MOVED_TASK_TO_READY_STATE(pxTCB)
/*-----------------------------------------------------------*/

//若句柄为null，返回当前tcb 否则返回任务句柄对应的tcb
#define prvGetTCBFromHandle(pxHandle) (((pxHandle) == NULL) ? pxCurrentTCB : (pxHandle))

//taskEVENT_LIST_ITEM_VALUE_IN_USE 是一个标记位，表示事件节点的值不是表示优先级，可能是其他目的（默认事件链表节点的值是任务的优先级）
#if (configUSE_16_BIT_TICKS == 1)
#define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U
#else
#define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL
#endif

/*
 * 任务控制块
 * 任务控制块包含一个任务运行的所有信息。任务的堆栈地址、状态等
 */
typedef struct tskTaskControlBlock
{
    volatile StackType_t *pxTopOfStack;       //指向任务栈顶 注意需要volatile修饰

    ListItem_t xStateListItem;                //任务状态节点、用于将任务挂在就绪、阻塞、挂起链表
    ListItem_t xEventListItem;                //将任务挂在事件链表（xPendingReadyList、其他用户创建的事件链表）
    UBaseType_t uxPriority;                   //任务优先级，0为最低
    StackType_t *pxStack;                     //指向任务栈基地址
    char pcTaskName[configMAX_TASK_NAME_LEN]; //任务名称

    StackType_t *pxEndOfStack;                //栈向上生长、指向堆栈最高有效地址

#if (portCRITICAL_NESTING_IN_TCB == 1)
    UBaseType_t uxCriticalNesting;            //临界区嵌套计数
#endif

#if (configUSE_TRACE_FACILITY == 1)
    UBaseType_t uxTCBNumber;  //任务PID
    UBaseType_t uxTaskNumber; // 任务id 用于debug
#endif


    UBaseType_t uxBasePriority;     //任务原始的优先级
    UBaseType_t uxMutexesHeld;      //拥有互斥锁的数量


//todo 任务运行时间
#if (configGENERATE_RUN_TIME_STATS == 1)
    uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
#endif

#if (configUSE_NEWLIB_REENTRANT == 1)

    /* Allocate a Newlib reent structure that is specific to this task.
         * Note Newlib support has been included by popular demand, but is not
         * used by the FreeRTOS maintainers themselves.  FreeRTOS is not
         * responsible for resulting newlib operation.  User must be familiar with
         * newlib and must provide system-wide implementations of the necessary
         * stubs. Be warned that (at the time of writing) the current newlib design
         * implements a system-wide malloc() that must be provided with locks.
         *
         * See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
         * for additional information. */
    struct _reent xNewLib_reent;
#endif
//todo 使用任务通知
#if (configUSE_TASK_NOTIFICATIONS == 1)
    volatile uint32_t ulNotifiedValue[configTASK_NOTIFICATION_ARRAY_ENTRIES];
    volatile uint8_t ucNotifyState[configTASK_NOTIFICATION_ARRAY_ENTRIES];
#endif

#if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0)
    uint8_t ucStaticallyAllocated; //为真时表示tcb是静态内存分配的
#endif

#if (INCLUDE_xTaskAbortDelay == 1)
    uint8_t ucDelayAborted;
#endif

#if (configUSE_POSIX_ERRNO == 1)
    int iTaskErrno;
#endif
} tskTCB;

typedef tskTCB TCB_t;

/*lint -save -e956 A manual analysis and inspection has been used to determine
 * which static variables must be declared volatile. */
PRIVILEGED_DATA TCB_t *volatile pxCurrentTCB = NULL;

//全局链表
PRIVILEGED_DATA static List_t pxReadyTasksLists[configMAX_PRIORITIES]; //就绪链表数组
PRIVILEGED_DATA static List_t xDelayedTaskList1;                       //延时链表1
PRIVILEGED_DATA static List_t xDelayedTaskList2;                       //延时链表2 用于时钟溢出
PRIVILEGED_DATA static List_t *volatile pxDelayedTaskList;             //指向当前正在使用的延时链表 注意volatile
PRIVILEGED_DATA static List_t *volatile pxOverflowDelayedTaskList;     //指向另一个没使用的延时链表
PRIVILEGED_DATA static List_t xPendingReadyList;                       //任务准备进入就绪链表，当任务就绪时，调度器被挂起，暂时无法进入就绪链表



PRIVILEGED_DATA static List_t xTasksWaitingTermination;                                     //任务被删除，但内存还未释放
PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = (UBaseType_t)0U; //已经被删除并且等待释放内存的任务的数量





PRIVILEGED_DATA static List_t xSuspendedTaskList; //任务挂起链表（任务呗挂起or无限期等待某个资源）



/* Global POSIX errno. Its value is changed upon context switching to match
 * the errno of the currently running task. */
#if (configUSE_POSIX_ERRNO == 1)
int FreeRTOS_errno = 0;
#endif

/* Other file private variables. --------------------------------*/
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = (UBaseType_t)0U; //当前任务数量
PRIVILEGED_DATA static volatile TickType_t xTickCount = (TickType_t)configINITIAL_TICK_COUNT;   //内核时钟计数值
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; //最高就绪优先级
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;            //标记调度器是否运行（挂起的调度器仍然是运行中，只有通过vTaskEndScheduler才能停止运行调度器）
PRIVILEGED_DATA static volatile TickType_t xPendedTicks = (TickType_t)0U;          //调度器挂起时错过的节拍数，需要在调度器恢复时补偿到xTickCount
PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;                //当有一个任务调度被挂起时为真
PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = (BaseType_t)0;        //todo 溢出次数
PRIVILEGED_DATA static UBaseType_t uxTaskNumber = (UBaseType_t)0U;                //任务的序号
PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = (TickType_t)0U; //延时队列下次唤醒时间
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL;                       

/* Improve support for OpenOCD. The kernel tracks Ready tasks via priority lists.
 * For tracking the state of remote threads, OpenOCD uses uxTopUsedPriority
 * to determine the number of priority lists to read back from the remote target. */
const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U;


/* 当调度器挂起时、上下文切换也被挂起，当前任务一直占有cpu。中断必须禁止修改TCB的xStateListItem。
 * 如果中断需要解锁一个任务、那先将任务的xEventListItem移动到xPendingReadyList 
 * 当调度器恢复时会将xPendingReadyList 的任务移动到readylist
 * 访问xPendingReadyList时，必须进入临界区
 */
//uxSchedulerSuspended大于0时 调度器挂起
PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = (UBaseType_t)pdFALSE;

#if (configGENERATE_RUN_TIME_STATS == 1)

/* Do not move these variables to function scope as doing so prevents the
 * code working with debuggers that need to remove the static qualifier. */
PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL;    /*< Holds the value of a timer/counter the last time a task was switched in. */
PRIVILEGED_DATA static volatile uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */

#endif

/*lint -restore */

/*-----------------------------------------------------------*/

/* File private functions. --------------------------------*/

//判断任务是否挂起（必须在临界区调用）
static BaseType_t prvTaskIsTaskSuspended(const TaskHandle_t xTask) PRIVILEGED_FUNCTION;



//初始化全局链表
static void prvInitialiseTaskLists(void) PRIVILEGED_FUNCTION;

/*
 * The idle task, which as all tasks is implemented as a never ending loop.
 * The idle task is automatically created and added to the ready lists upon
 * creation of the first user task.
 *
 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
 * language extensions.  The equivalent prototype for this function is:
 *
 * void prvIdleTask( void *pvParameters );
 *
 */

static portTASK_FUNCTION_PROTO(prvIdleTask, pvParameters) PRIVILEGED_FUNCTION;

#if (INCLUDE_vTaskDelete == 1)

static void prvDeleteTCB(TCB_t *pxTCB) PRIVILEGED_FUNCTION;

#endif

//释放xTasksWaitingTermination链表中的任务资源（由空闲任务调用）
static void prvCheckTasksWaitingTermination(void) PRIVILEGED_FUNCTION;

/*
 * 添加当前任务到延时链表。当xTicksToWait最大且xCanBlockIndefinitely真时，任务是进入挂起链表、不会被时钟中断唤醒，因为任务等待的不是一个确定的时间
 * xTicksToWait 延时时钟
 * xCanBlockIndefinitely 是否无限延时
 */
static void prvAddCurrentTaskToDelayedList(TickType_t xTicksToWait,
                                           const BaseType_t xCanBlockIndefinitely) PRIVILEGED_FUNCTION;

/*
 * Fills an TaskStatus_t structure with information on each task that is
 * referenced from the pxList list (which may be a ready list, a delayed list,
 * a suspended list, etc.).
 *
 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
 * NORMAL APPLICATION CODE.
 */
#if (configUSE_TRACE_FACILITY == 1)

static UBaseType_t prvListTasksWithinSingleList(TaskStatus_t *pxTaskStatusArray,
                                                List_t *pxList,
                                                eTaskState eState) PRIVILEGED_FUNCTION;

#endif

//在指定链表中搜索指定名称的任务、返回任务句柄
#if (INCLUDE_xTaskGetHandle == 1)

static TCB_t *prvSearchForNameWithinSingleList(List_t *pxList,
                                               const char pcNameToQuery[]) PRIVILEGED_FUNCTION;

#endif

//检测任务的堆栈剩余大小
#if ((configUSE_TRACE_FACILITY == 1) || (INCLUDE_uxTaskGetStackHighWaterMark == 1) || (INCLUDE_uxTaskGetStackHighWaterMark2 == 1))

static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace(const uint8_t *pucStackByte) PRIVILEGED_FUNCTION;

#endif

/*
 * Return the amount of time, in ticks, that will pass before the kernel will
 * next move a task from the Blocked state to the Running state.
 *
 * This conditional compilation should use inequality to 0, not equality to 1.
 * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user
 * defined low power mode implementations require configUSE_TICKLESS_IDLE to be
 * set to a value other than 1.
 */
#if (configUSE_TICKLESS_IDLE != 0)

static TickType_t prvGetExpectedIdleTime(void) PRIVILEGED_FUNCTION;

#endif

/*
 * 设置全局变量xNextTaskUnblockTime为下一个任务解锁的时间（需要在临界区执行，防止延时链表被修改）
 */
static void prvResetNextTaskUnblockTime(void) PRIVILEGED_FUNCTION;

#if ((configUSE_TRACE_FACILITY == 1) && (configUSE_STATS_FORMATTING_FUNCTIONS > 0))

/*
 * Helper function used to pad task names with spaces when printing out
 * human readable tables of task information.
 */
static char *prvWriteNameToBuffer(char *pcBuffer,
                                  const char *pcTaskName) PRIVILEGED_FUNCTION;

#endif

//任务tcb和栈内存分配完成后，调用该函数填充tcb的成员
static void prvInitialiseNewTask(TaskFunction_t pxTaskCode,
                                 const char *const pcName,
                                 const uint32_t ulStackDepth,
                                 void *const pvParameters,
                                 UBaseType_t uxPriority,
                                 TaskHandle_t *const pxCreatedTask,
                                 TCB_t *pxNewTCB,
                                 const MemoryRegion_t *const xRegions) PRIVILEGED_FUNCTION;

//将新的任务添加到就绪链表以给调度器调度
static void prvAddNewTaskToReadyList(TCB_t *pxNewTCB) PRIVILEGED_FUNCTION;

/*
 * freertos_tasks_c_additions_init() should only be called if the user definable
 * macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro
 * called by the function.
 */
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT

static void freertos_tasks_c_additions_init(void) PRIVILEGED_FUNCTION;

#endif

/*-----------------------------------------------------------*/

#if (configSUPPORT_STATIC_ALLOCATION == 1)

TaskHandle_t xTaskCreateStatic(TaskFunction_t pxTaskCode,
                               const char *const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                               const uint32_t ulStackDepth,
                               void *const pvParameters,
                               UBaseType_t uxPriority,
                               StackType_t *const puxStackBuffer,
                               StaticTask_t *const pxTaskBuffer)
{
    TCB_t *pxNewTCB;
    TaskHandle_t xReturn;
    //检测内存
    configASSERT(puxStackBuffer != NULL);
    configASSERT(pxTaskBuffer != NULL);

#if (configASSERT_DEFINED == 1)
    {
        /* Sanity check that the size of the structure used to declare a
                 * variable of type StaticTask_t equals the size of the real task
                 * structure. */
        volatile size_t xSize = sizeof(StaticTask_t);
        configASSERT(xSize == sizeof(TCB_t));
        (void)xSize; /* Prevent lint warning when configASSERT() is not used. */
    }
#endif /* configASSERT_DEFINED */

    if ((pxTaskBuffer != NULL) && (puxStackBuffer != NULL))
    {

        pxNewTCB = (TCB_t *)pxTaskBuffer;
        pxNewTCB->pxStack = (StackType_t *)puxStackBuffer;

#if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0)
        {
            //标记该tcb是由静态分配的
            pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
        }
#endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */

        prvInitialiseNewTask(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL);
        prvAddNewTaskToReadyList(pxNewTCB);
    }
    else
    {
        xReturn = NULL;
    }

    return xReturn;
}

#endif /* SUPPORT_STATIC_ALLOCATION */

/*-----------------------------------------------------------*/

#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)

BaseType_t xTaskCreate(TaskFunction_t pxTaskCode,
                       const char *const pcName,
                       const configSTACK_DEPTH_TYPE usStackDepth,
                       void *const pvParameters,
                       UBaseType_t uxPriority,
                       TaskHandle_t *const pxCreatedTask)
{
    TCB_t *pxNewTCB;
    BaseType_t xReturn;

//若栈向上生长，则先分配tcb，后分配栈，防止栈覆盖了tcb（tcb地址小于栈基地址）
#if (portSTACK_GROWTH > 0)
    {
        pxNewTCB = (TCB_t *)pvPortMalloc(sizeof(TCB_t));

        if (pxNewTCB != NULL)
        {
            //申请一段内存作为栈、地址保存在tcb中，后续可释放
            pxNewTCB->pxStack = (StackType_t *)pvPortMalloc((((size_t)usStackDepth) * sizeof(StackType_t)));

            if (pxNewTCB->pxStack == NULL)
            {

                vPortFree(pxNewTCB);
                pxNewTCB = NULL;
            }
        }
    }
#else  /* portSTACK_GROWTH */
    {
        //若栈向下生长，则先分配栈，后分配tcb，防止栈覆盖了tcb（tcb地址大于栈基地址）
        StackType_t *pxStack;

        pxStack = pvPortMalloc((((size_t)usStackDepth) * sizeof(StackType_t)));

        if (pxStack != NULL)
        {

            pxNewTCB = (TCB_t *)pvPortMalloc(sizeof(TCB_t));

            if (pxNewTCB != NULL)
            {

                pxNewTCB->pxStack = pxStack;
            }
            else
            {

                vPortFree(pxStack);
            }
        }
        else
        {
            pxNewTCB = NULL;
        }
    }
#endif /* portSTACK_GROWTH */

    if (pxNewTCB != NULL)
    {
#if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0)
        {
            //标记tcb的内存分配方式为动态内存
            pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
        }
#endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
        //初始化新任务
        prvInitialiseNewTask(pxTaskCode, pcName, (uint32_t)usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL);
        //插入就绪表
        prvAddNewTaskToReadyList(pxNewTCB);
        xReturn = pdPASS;
    }
    else
    {
        xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
    }

    return xReturn;
}

#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
/*-----------------------------------------------------------*/

static void prvInitialiseNewTask(TaskFunction_t pxTaskCode,
                                 const char *const pcName,
                                 const uint32_t ulStackDepth,
                                 void *const pvParameters,
                                 UBaseType_t uxPriority,
                                 TaskHandle_t *const pxCreatedTask,
                                 TCB_t *pxNewTCB,
                                 const MemoryRegion_t *const xRegions)
{
    StackType_t *pxTopOfStack;
    UBaseType_t x;
//设置堆栈地址

    {
        //初始化堆栈为默认值、帮助debug
        (void)memset(pxNewTCB->pxStack, (int)tskSTACK_FILL_BYTE, (size_t)ulStackDepth * sizeof(StackType_t));
    }


#if (portSTACK_GROWTH < 0)
    {
        //栈向下生长、故初始化后的栈顶在高地址
        pxTopOfStack = &(pxNewTCB->pxStack[ulStackDepth - (uint32_t)1]);
        //TODO 堆栈的边沿对齐计算方式  pxTopOfStack & 0xfff8 地址是8的倍数
        pxTopOfStack = (StackType_t *)(((portPOINTER_SIZE_TYPE)pxTopOfStack) & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));

        //检测边沿对齐是否正确
        configASSERT((((portPOINTER_SIZE_TYPE)pxTopOfStack & (portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK) == 0UL));
    }
#else  /* portSTACK_GROWTH */
    {
        //堆栈向上生长、初始化栈顶指针在低地址 也就是数组起始地址
        pxTopOfStack = pxNewTCB->pxStack;

        //TODO 为何在这里没有内存对齐？可能是内存在分配时就考虑到？
        configASSERT((((portPOINTER_SIZE_TYPE)pxNewTCB->pxStack & (portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK) == 0UL));

        //设置堆栈最高有效地址
        pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + (ulStackDepth - (uint32_t)1);
    }
#endif /* portSTACK_GROWTH */

    //复制任务名称到TCB
    if (pcName != NULL)
    {
        for (x = (UBaseType_t)0; x < (UBaseType_t)configMAX_TASK_NAME_LEN; x++)
        {
            pxNewTCB->pcTaskName[x] = pcName[x];

            if (pcName[x] == (char)0x00)
            {
                break;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        //确保字符串的正确结束
        pxNewTCB->pcTaskName[configMAX_TASK_NAME_LEN - 1] = '\0';
    }
    else
    {
        pxNewTCB->pcTaskName[0] = 0x00;
    }

    //设置任务优先级
    if (uxPriority >= (UBaseType_t)configMAX_PRIORITIES)
    {
        uxPriority = (UBaseType_t)configMAX_PRIORITIES - (UBaseType_t)1U;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    pxNewTCB->uxPriority = uxPriority;


    {
        pxNewTCB->uxBasePriority = uxPriority;  
        pxNewTCB->uxMutexesHeld = 0;
    }


    //初始化任务的节点
    vListInitialiseItem(&(pxNewTCB->xStateListItem));
    vListInitialiseItem(&(pxNewTCB->xEventListItem));

    listSET_LIST_ITEM_OWNER(&(pxNewTCB->xStateListItem), pxNewTCB);

    //设置事件节点的值，优先级越高、节点值越小，在链表中排序越靠前
    listSET_LIST_ITEM_VALUE(&(pxNewTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)uxPriority);
    listSET_LIST_ITEM_OWNER(&(pxNewTCB->xEventListItem), pxNewTCB);

#if (portCRITICAL_NESTING_IN_TCB == 1)
    {
        pxNewTCB->uxCriticalNesting = (UBaseType_t)0U;
    }
#endif /* portCRITICAL_NESTING_IN_TCB */

#if (configUSE_TASK_NOTIFICATIONS == 1)
    {
        memset((void *)&(pxNewTCB->ulNotifiedValue[0]), 0x00, sizeof(pxNewTCB->ulNotifiedValue));
        memset((void *)&(pxNewTCB->ucNotifyState[0]), 0x00, sizeof(pxNewTCB->ucNotifyState));
    }
#endif

#if (configUSE_NEWLIB_REENTRANT == 1)
    {
        /* Initialise this task's Newlib reent structure.
             * See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
             * for additional information. */
        _REENT_INIT_PTR((&(pxNewTCB->xNewLib_reent)));
    }
#endif

#if (INCLUDE_xTaskAbortDelay == 1)
    {
        pxNewTCB->ucDelayAborted = pdFALSE;
    }
#endif

    //初始化任务的堆栈使其看起来任务好像已经在运行了，这里需要根据硬件实现
    {
/* If the port has capability to detect stack overflow,
             * pass the stack end address to the stack initialization
             * function as well. */
#if (portHAS_STACK_OVERFLOW_CHECKING == 1)
        {
#if (portSTACK_GROWTH < 0)
            {
                pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxNewTCB->pxStack, pxTaskCode, pvParameters);
            }
#else  /* portSTACK_GROWTH */
            {
                pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxNewTCB->pxEndOfStack, pxTaskCode, pvParameters);
            }
#endif /* portSTACK_GROWTH */
        }
#else  /* portHAS_STACK_OVERFLOW_CHECKING */
        {
            pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters);
        }
#endif /* portHAS_STACK_OVERFLOW_CHECKING */
    }

    if (pxCreatedTask != NULL)
    {
        //返回任务的句柄
        *pxCreatedTask = (TaskHandle_t)pxNewTCB;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}
/*-----------------------------------------------------------*/

static void prvAddNewTaskToReadyList(TCB_t *pxNewTCB)
{
    //todo 进入临界区，防止中断修改pxCurrentTCB
    taskENTER_CRITICAL();
    {
        uxCurrentNumberOfTasks++; //任务数量+1

        //判断是否是第一个运行的任务
        if (pxCurrentTCB == NULL)
        {
            //当前没有任务正在使用cpu，那么新的任务就开始使用cpu
            pxCurrentTCB = pxNewTCB;

            if (uxCurrentNumberOfTasks == (UBaseType_t)1)
            {
                //第一个运行的任务、做一些必须的初始化工作
                prvInitialiseTaskLists();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            //若调度器关闭了，且新任务优先级大于当前任务优先级、更新pxCurrentTCB
            if (xSchedulerRunning == pdFALSE)
            {
                if (pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority)
                {
                    pxCurrentTCB = pxNewTCB;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }

        uxTaskNumber++;

#if (configUSE_TRACE_FACILITY == 1)
        {
            /* Add a counter into the TCB for tracing only. */
            pxNewTCB->uxTCBNumber = uxTaskNumber;
        }
#endif /* configUSE_TRACE_FACILITY */
        traceTASK_CREATE(pxNewTCB);
        //将控制块添加到就绪链表
        prvAddTaskToReadyList(pxNewTCB);

        portSETUP_TCB(pxNewTCB);
    }
    taskEXIT_CRITICAL(); 

    if (xSchedulerRunning != pdFALSE)
    {
        //若调度器正在运行且 新任务优先级高，发生抢占
        if (pxCurrentTCB->uxPriority < pxNewTCB->uxPriority)
        {
            //todo 任务抢占切换
            taskYIELD_IF_USING_PREEMPTION();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}
/*-----------------------------------------------------------*/

void vTaskDelete(TaskHandle_t xTaskToDelete)
{
    TCB_t *pxTCB;
    //进入临界区，防止中断修改xEventListItem
    taskENTER_CRITICAL();
    {
        //获取即将删除的tcb
        pxTCB = prvGetTCBFromHandle(xTaskToDelete);

        //将任务的状态节点移除链表 并重置就绪链表
        if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0)
        {
            taskRESET_READY_PRIORITY(pxTCB->uxPriority);
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        //若任务在等待某件事件、则移除该事件链表
        if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL)
        {
            (void)uxListRemove(&(pxTCB->xEventListItem));
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        uxTaskNumber++; 

        if (pxTCB == pxCurrentTCB)
        {

            //任务删除自己、需要将任务插入任务终止链表、由空闲任务来释放内存
            vListInsertEnd(&xTasksWaitingTermination, &(pxTCB->xStateListItem));

            ++uxDeletedTasksWaitingCleanUp; //标记有任务需要被释放内存

            traceTASK_DELETE(pxTCB);

            /* The pre-delete hook is primarily for the Windows simulator,
                 * in which Windows specific clean up operations are performed,
                 * after which it is not possible to yield away from this task -
                 * hence xYieldPending is used to latch that a context switch is
                 * required. */

            portPRE_TASK_DELETE_HOOK(pxTCB, &xYieldPending);
        }
        else
        {
            --uxCurrentNumberOfTasks;   //当前任务总数减少1
            traceTASK_DELETE(pxTCB);
            prvDeleteTCB(pxTCB);    //释放内存

            //重置下次解锁时间
            prvResetNextTaskUnblockTime();
        }
    }
    taskEXIT_CRITICAL();

    //若刚刚删除的是正在运行的任务 则强制任务调度
    if (xSchedulerRunning != pdFALSE)
    {
        if (pxTCB == pxCurrentTCB)
        {
            configASSERT(uxSchedulerSuspended == 0);
            portYIELD_WITHIN_API();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
}

/*-----------------------------------------------------------*/

BaseType_t xTaskDelayUntil(TickType_t *const pxPreviousWakeTime,
                           const TickType_t xTimeIncrement)
{
    TickType_t xTimeToWake;
    BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;

    configASSERT(pxPreviousWakeTime);
    configASSERT((xTimeIncrement > 0U));
    configASSERT(uxSchedulerSuspended == 0);
    //挂起任务调度器 防止其他任务修改延时链表。中断不会修改延时链表，不需要进入临界段
    vTaskSuspendAll();
    {
        //保证xTickCount在本代码块内不会被修改
        const TickType_t xConstTickCount = xTickCount;

        //计算下次唤醒时间
        xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;

        if (xConstTickCount < *pxPreviousWakeTime)
        {
            // -----cur++++++pre----- 只有当xTimeToWake在+号时才能进入延时
            if ((xTimeToWake < *pxPreviousWakeTime) && (xTimeToWake > xConstTickCount))
            {
                xShouldDelay = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            // +++++pre-----cur++++++ 只有当xTimeToWake在+号时才能进入延时
            if ((xTimeToWake < *pxPreviousWakeTime) || (xTimeToWake > xConstTickCount))
            {
                xShouldDelay = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }

        //更新pxPreviousWakeTime
        *pxPreviousWakeTime = xTimeToWake;

        if (xShouldDelay != pdFALSE)
        {
            traceTASK_DELAY_UNTIL(xTimeToWake);

            //中断不会修改delayed链表，故不需要进入临界区
            //prvAddCurrentTaskToDelayedList需要的是相对延时时间 故是xTimeToWake - xConstTickCount
            prvAddCurrentTaskToDelayedList(xTimeToWake - xConstTickCount, pdFALSE);
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    //恢复调度器、执行任务调度
    xAlreadyYielded = xTaskResumeAll();

    if (xAlreadyYielded == pdFALSE)
    {
        portYIELD_WITHIN_API();
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return xShouldDelay;
}

/*-----------------------------------------------------------*/

void vTaskDelay(const TickType_t xTicksToDelay)
{
    BaseType_t xAlreadyYielded = pdFALSE;
    

    if (xTicksToDelay > (TickType_t)0U)
    {
        configASSERT(uxSchedulerSuspended == 0);
        //挂起任务调度器 防止其他任务修改延时链表。中断不会修改延时链表，不需要进入临界段
        vTaskSuspendAll();
        {
            traceTASK_DELAY();

            //当调度器挂起时，任务不能插入就绪表
            //添加当前任务到延时链表
            prvAddCurrentTaskToDelayedList(xTicksToDelay, pdFALSE);
        }
        //恢复调度器、若恢复调度器时、已经完成一次任务调度、则接下来不需要再产生一次任务调度
        xAlreadyYielded = xTaskResumeAll();
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    //若调度器恢复时未进行任务调度，则启动一次任务调度
    if (xAlreadyYielded == pdFALSE)
    {
        portYIELD_WITHIN_API();
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

/*-----------------------------------------------------------*/

#if ((INCLUDE_eTaskGetState == 1) || (configUSE_TRACE_FACILITY == 1) || (INCLUDE_xTaskAbortDelay == 1))

eTaskState eTaskGetState(TaskHandle_t xTask)
{
    eTaskState eReturn;
    List_t const *pxStateList, *pxDelayedList, *pxOverflowedDelayedList;
    const TCB_t *const pxTCB = xTask;

    configASSERT(pxTCB);

    if (pxTCB == pxCurrentTCB)
    {
        /* The task calling this function is querying its own state. */
        eReturn = eRunning;
    }
    else
    {
        //todo 获取TCB所在链表需要临界保护 中断可能修改延时链表吗
        taskENTER_CRITICAL();
        {
            pxStateList = listLIST_ITEM_CONTAINER(&(pxTCB->xStateListItem));
            pxDelayedList = pxDelayedTaskList;
            pxOverflowedDelayedList = pxOverflowDelayedTaskList;
        }
        taskEXIT_CRITICAL();

        if ((pxStateList == pxDelayedList) || (pxStateList == pxOverflowedDelayedList))
        {
            //任务处于延时阻塞态
            eReturn = eBlocked;
        }


        else if (pxStateList == &xSuspendedTaskList)
        {
            //任务挂起了，那他可能是无限期延时或者真的被挂起
            //若xEventListItem不为null则说明任务在等待事件，否则任务被无限期延时
            if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL)
            {
#if (configUSE_TASK_NOTIFICATIONS == 1)
                {
                    BaseType_t x;

                    /* The task does not appear on the event list item of
                                 * and of the RTOS objects, but could still be in the
                                 * blocked state if it is waiting on its notification
                                 * rather than waiting on an object.  If not, is
                                 * suspended. */
                    eReturn = eSuspended;

                    for (x = 0; x < configTASK_NOTIFICATION_ARRAY_ENTRIES; x++)
                    {
                        if (pxTCB->ucNotifyState[x] == taskWAITING_NOTIFICATION)
                        {
                            eReturn = eBlocked;
                            break;
                        }
                    }
                }
#else  /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
                {
                    eReturn = eSuspended;
                }
#endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
            }
            else
            {
                eReturn = eBlocked;
            }
        }


#if (INCLUDE_vTaskDelete == 1)
        else if ((pxStateList == &xTasksWaitingTermination) || (pxStateList == NULL))
        {
            //任务在等待被删除或者 不在任何链表中，说明已经删除了
            eReturn = eDeleted;
        }
#endif

        else
        {
            eReturn = eReady;
        }
    }

    return eReturn;
}

#endif /* INCLUDE_eTaskGetState */
/*-----------------------------------------------------------*/

#if (INCLUDE_uxTaskPriorityGet == 1)

UBaseType_t uxTaskPriorityGet(const TaskHandle_t xTask)
{
    TCB_t const *pxTCB;
    UBaseType_t uxReturn;
    //todo 防止中断会修改任务优先级
    taskENTER_CRITICAL();
    {
        pxTCB = prvGetTCBFromHandle(xTask);
        uxReturn = pxTCB->uxPriority;
    }
    taskEXIT_CRITICAL();

    return uxReturn;
}

#endif /* INCLUDE_uxTaskPriorityGet */
/*-----------------------------------------------------------*/

#if (INCLUDE_uxTaskPriorityGet == 1)

UBaseType_t uxTaskPriorityGetFromISR(const TaskHandle_t xTask)
{
    TCB_t const *pxTCB;
    UBaseType_t uxReturn, uxSavedInterruptState;

    /* RTOS ports that support interrupt nesting have the concept of a
         * maximum  system call (or maximum API call) interrupt priority.
         * Interrupts that are  above the maximum system call priority are keep
         * permanently enabled, even when the RTOS kernel is in a critical section,
         * but cannot make any calls to FreeRTOS API functions.  If configASSERT()
         * is defined in FreeRTOSConfig.h then
         * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
         * failure if a FreeRTOS API function is called from an interrupt that has
         * been assigned a priority above the configured maximum system call
         * priority.  Only FreeRTOS functions that end in FromISR can be called
         * from interrupts  that have been assigned a priority at or (logically)
         * below the maximum system call interrupt priority.  FreeRTOS maintains a
         * separate interrupt safe API to ensure interrupt entry is as fast and as
         * simple as possible.  More information (albeit Cortex-M specific) is
         * provided on the following link:
         * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
    portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
    //进入临界区 
    uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        pxTCB = prvGetTCBFromHandle(xTask);
        uxReturn = pxTCB->uxPriority;
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptState);

    return uxReturn;
}

#endif /* INCLUDE_uxTaskPriorityGet */
/*-----------------------------------------------------------*/

#if (INCLUDE_vTaskPrioritySet == 1)

void vTaskPrioritySet(TaskHandle_t xTask,
                      UBaseType_t uxNewPriority)
{
    TCB_t *pxTCB;
    UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
    BaseType_t xYieldRequired = pdFALSE;

    configASSERT((uxNewPriority < configMAX_PRIORITIES));

    //确保优先级合法
    if (uxNewPriority >= (UBaseType_t)configMAX_PRIORITIES)
    {
        uxNewPriority = (UBaseType_t)configMAX_PRIORITIES - (UBaseType_t)1U;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
    //进入临界区、防止就绪链表、任务控制块被修改
    taskENTER_CRITICAL();
    {
        //获取任务句柄
        pxTCB = prvGetTCBFromHandle(xTask);

        traceTASK_PRIORITY_SET(pxTCB, uxNewPriority);


        {
            uxCurrentBasePriority = pxTCB->uxBasePriority;
        }


        if (uxCurrentBasePriority != uxNewPriority)
        {
            //提升优先级
            if (uxNewPriority > uxCurrentBasePriority)
            {
                if (pxTCB != pxCurrentTCB)
                {
                    //新的优先级比当前的任务优先级高时，需要任务调度
                    if (uxNewPriority >= pxCurrentTCB->uxPriority)
                    {
                        xYieldRequired = pdTRUE;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                else
                {
                    //当前运行的任务优先级升高，不需要任务调度
                }
            }
            else if (pxTCB == pxCurrentTCB)
            {
                //降低优先级且是当前运行的任务、需要任务调度
                xYieldRequired = pdTRUE;
            }
            else
            {
                //非当前任务优先级降低、不需要调度
            }

            //uxPriorityUsedOnEntry用于定位任务所在的优先级链表
            uxPriorityUsedOnEntry = pxTCB->uxPriority;


            {
                /* Only change the priority being used if the task is not
                         * currently using an inherited priority. */
                if (pxTCB->uxBasePriority == pxTCB->uxPriority)
                {
                    pxTCB->uxPriority = uxNewPriority;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                /* The base priority gets set whatever. */
                pxTCB->uxBasePriority = uxNewPriority;
            }


            //事件节点的值 与优先级大小相关， 需要修改
            if ((listGET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem)) & taskEVENT_LIST_ITEM_VALUE_IN_USE) == 0UL)
            {
                listSET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem), ((TickType_t)configMAX_PRIORITIES - (TickType_t)uxNewPriority));
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            //移动任务在就绪链表中的位置，处于挂起和阻塞态的任务不需要移动
            if (listIS_CONTAINED_WITHIN(&(pxReadyTasksLists[uxPriorityUsedOnEntry]), &(pxTCB->xStateListItem)) != pdFALSE)
            {
                //移出旧的优先级链表
                if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0)
                {
                    //todo portRESET_READY_PRIORITY
                    portRESET_READY_PRIORITY(uxPriorityUsedOnEntry, uxTopReadyPriority);
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
                //插入新的优先级链表
                prvAddTaskToReadyList(pxTCB);
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
            //todo 临界区内进行任务调度？
            if (xYieldRequired != pdFALSE)
            {
                taskYIELD_IF_USING_PREEMPTION();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            /* Remove compiler warning about unused variables when the port
                 * optimised task selection is not being used. */
            (void)uxPriorityUsedOnEntry;
        }
    }
    taskEXIT_CRITICAL();
}

#endif /* INCLUDE_vTaskPrioritySet */
/*-----------------------------------------------------------*/



void vTaskSuspend(TaskHandle_t xTaskToSuspend)
{
    TCB_t *pxTCB;
    //进入临界区 防止防止就绪链表、挂起链表被修改
    taskENTER_CRITICAL();
    {
        //获取任务tcb
        pxTCB = prvGetTCBFromHandle(xTaskToSuspend);

        traceTASK_SUSPEND(pxTCB);

        //从就绪/阻塞链表中移除任务
        if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0)
        {
            taskRESET_READY_PRIORITY(pxTCB->uxPriority);
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        //从事件链表中移除任务
        if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL)
        {
            (void)uxListRemove(&(pxTCB->xEventListItem));
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
        //将任务插入挂起链表
        vListInsertEnd(&xSuspendedTaskList, &(pxTCB->xStateListItem));

#if (configUSE_TASK_NOTIFICATIONS == 1)
        {
            BaseType_t x;

            for (x = 0; x < configTASK_NOTIFICATION_ARRAY_ENTRIES; x++)
            {
                if (pxTCB->ucNotifyState[x] == taskWAITING_NOTIFICATION)
                {
                    /* The task was blocked to wait for a notification, but is
                             * now suspended, so no notification was received. */
                    pxTCB->ucNotifyState[x] = taskNOT_WAITING_NOTIFICATION;
                }
            }
        }
#endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
    }
    taskEXIT_CRITICAL();

    if (xSchedulerRunning != pdFALSE)
    {
        //更新下次任务解锁时间。刚刚挂起的任务可能是下个解锁的任务
        taskENTER_CRITICAL();
        {
            prvResetNextTaskUnblockTime();
        }
        taskEXIT_CRITICAL();
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    //挂起任务是正在运行的任务
    if (pxTCB == pxCurrentTCB)
    {
        if (xSchedulerRunning != pdFALSE)
        {
            //当前任务被挂起，执行一次任务调度
            configASSERT(uxSchedulerSuspended == 0);
            portYIELD_WITHIN_API();
        }
        else    //todo 调度器关闭所以必须调整pxCurrentTCB
        {
            
            if (listCURRENT_LIST_LENGTH(&xSuspendedTaskList) == uxCurrentNumberOfTasks)
            {
                //所有任务都被挂起 pxCurrentTCB为null，下次创建新任务时，就执行新任务
                pxCurrentTCB = NULL;
            }
            else
            {
                //更新pxCurrentTCB
                vTaskSwitchContext();
            }
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}


/*-----------------------------------------------------------*/



static BaseType_t prvTaskIsTaskSuspended(const TaskHandle_t xTask)
{
    BaseType_t xReturn = pdFALSE;
    const TCB_t *const pxTCB = xTask;


    //挂起的任务必须不为null
    configASSERT(xTask);

    //判断任务是否在挂起链表
    if (listIS_CONTAINED_WITHIN(&xSuspendedTaskList, &(pxTCB->xStateListItem)) != pdFALSE)
    {
        //因为访问xPendingReadyList所以必须在临界区调用本函数
        if (listIS_CONTAINED_WITHIN(&xPendingReadyList, &(pxTCB->xEventListItem)) == pdFALSE)
        {

            if (listIS_CONTAINED_WITHIN(NULL, &(pxTCB->xEventListItem)) != pdFALSE) 
            {
                //确实是在等待某一事件 或者无限期延时
                xReturn = pdTRUE;
            }
            else    //只是在延时链表
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else    //任务已经被中断挂到xPendingReadyList链表、只是调度器也被挂起、其已经不是挂起态
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return xReturn;
} /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */


/*-----------------------------------------------------------*/



void vTaskResume(TaskHandle_t xTaskToResume)
{
    TCB_t *const pxTCB = xTaskToResume;

    configASSERT(xTaskToResume);

    //恢复的任务不可能是null 并且 不可能是正在运行的任务
    if ((pxTCB != pxCurrentTCB) && (pxTCB != NULL))
    {
        taskENTER_CRITICAL();
        {
            if (prvTaskIsTaskSuspended(pxTCB) != pdFALSE)
            {
                traceTASK_RESUME(pxTCB);

                //移出挂起链表、加入就绪链表
                (void)uxListRemove(&(pxTCB->xStateListItem));
                prvAddTaskToReadyList(pxTCB);

                //恢复任务的优先级较高、进行任务调度
                if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority)
                {

                    taskYIELD_IF_USING_PREEMPTION();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        taskEXIT_CRITICAL();
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}



/*-----------------------------------------------------------*/



BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
{
    BaseType_t xYieldRequired = pdFALSE; //任务调度标记 由于中断中不能执行上下文切换、故使用他来代替上下文切换
    TCB_t *const pxTCB = xTaskToResume;
    UBaseType_t uxSavedInterruptStatus;

    configASSERT(xTaskToResume);

    /* RTOS ports that support interrupt nesting have the concept of a
         * maximum  system call (or maximum API call) interrupt priority.
         * Interrupts that are  above the maximum system call priority are keep
         * permanently enabled, even when the RTOS kernel is in a critical section,
         * but cannot make any calls to FreeRTOS API functions.  If configASSERT()
         * is defined in FreeRTOSConfig.h then
         * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
         * failure if a FreeRTOS API function is called from an interrupt that has
         * been assigned a priority above the configured maximum system call
         * priority.  Only FreeRTOS functions that end in FromISR can be called
         * from interrupts  that have been assigned a priority at or (logically)
         * below the maximum system call interrupt priority.  FreeRTOS maintains a
         * separate interrupt safe API to ensure interrupt entry is as fast and as
         * simple as possible.  More information (albeit Cortex-M specific) is
         * provided on the following link:
         * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
    portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
    //进入中断级临界区
    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 
    {
        //判断是否真的挂起
        if (prvTaskIsTaskSuspended(pxTCB) != pdFALSE)
        {
            traceTASK_RESUME_FROM_ISR(pxTCB);

            if (uxSchedulerSuspended == (UBaseType_t)pdFALSE)
            {
                //调度器运行中、若任务优先级更高、则产生任务调度
                if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority)
                {
                    xYieldRequired = pdTRUE; //需要进行任务调度

                    xYieldPending = pdTRUE; //一个任务调度请求被挂起
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
                //将任务移动到就绪链表
                (void)uxListRemove(&(pxTCB->xStateListItem));
                prvAddTaskToReadyList(pxTCB);
            }
            else
            {
                //调度器挂起 不能在中断中直接修改就绪链表，先将任务缓存到xPendingReadyList
                vListInsertEnd(&(xPendingReadyList), &(pxTCB->xEventListItem));
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);

    return xYieldRequired;
}


/*-----------------------------------------------------------*/

void vTaskStartScheduler(void)
{
    BaseType_t xReturn;

//使用用户分配的内存创建空闲任务
#if (configSUPPORT_STATIC_ALLOCATION == 1)
    {
        StaticTask_t *pxIdleTaskTCBBuffer = NULL;
        StackType_t *pxIdleTaskStackBuffer = NULL;
        uint32_t ulIdleTaskStackSize;

        //用户自行设置空闲任务的内存
        vApplicationGetIdleTaskMemory(&pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize);
        xIdleTaskHandle = xTaskCreateStatic(prvIdleTask,
                                            configIDLE_TASK_NAME,
                                            ulIdleTaskStackSize,
                                            (void *)NULL,      /*lint !e961.  The cast is not redundant for all compilers. */
                                            portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                            pxIdleTaskStackBuffer,
                                            pxIdleTaskTCBBuffer); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */

        if (xIdleTaskHandle != NULL)
        {
            xReturn = pdPASS;
        }
        else
        {
            xReturn = pdFAIL;
        }
    }
#else  /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
    {
        //使用动态内存分配空闲任务
        xReturn = xTaskCreate(prvIdleTask,
                              configIDLE_TASK_NAME,
                              configMINIMAL_STACK_SIZE,
                              (void *)NULL,
                              portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                              &xIdleTaskHandle); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
    }
#endif /* configSUPPORT_STATIC_ALLOCATION */

#if (configUSE_TIMERS == 1)
    {
        if (xReturn == pdPASS)
        {
            xReturn = xTimerCreateTimerTask();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
#endif /* configUSE_TIMERS */

    if (xReturn == pdPASS)
    {
/* freertos_tasks_c_additions_init() should only be called if the user
         * definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is
         * the only macro called by the function. */
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
        {
            freertos_tasks_c_additions_init();
        }
#endif

        //关闭中断、稍后再第一个任务开始运行时，中断会被打开
        portDISABLE_INTERRUPTS();

#if (configUSE_NEWLIB_REENTRANT == 1)
        {
            /* Switch Newlib's _impure_ptr variable to point to the _reent
                 * structure specific to the task that will run first.
                 * See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
                 * for additional information. */
            _impure_ptr = &(pxCurrentTCB->xNewLib_reent);
        }
#endif /* configUSE_NEWLIB_REENTRANT */

        //初始化调度器的一些参数
        xNextTaskUnblockTime = portMAX_DELAY;
        xSchedulerRunning = pdTRUE;
        xTickCount = (TickType_t)configINITIAL_TICK_COUNT;

        /* If configGENERATE_RUN_TIME_STATS is defined then the following
         * macro must be defined to configure the timer/counter used to generate
         * the run time counter time base.   NOTE:  If configGENERATE_RUN_TIME_STATS
         * is set to 0 and the following line fails to build then ensure you do not
         * have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
         * FreeRTOSConfig.h file. */
        portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();

        traceTASK_SWITCHED_IN();

        //启动调度器硬件层接口
        if (xPortStartScheduler() != pdFALSE)
        {
            //启动调度器后、程序不应该运行到此
        }
        else
        {
            /* Should only reach here if a task calls xTaskEndScheduler(). */
        }
    }
    else
    {
        /* This line will only be reached if the kernel could not be started,
         * because there was not enough FreeRTOS heap to create the idle task
         * or the timer task. */
        configASSERT(xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY);
    }

    /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,
     * meaning xIdleTaskHandle is not used anywhere else. */
    (void)xIdleTaskHandle;

    /* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority
     * from getting optimized out as it is no longer used by the kernel. */
    (void)uxTopUsedPriority;
}
/*-----------------------------------------------------------*/

void vTaskEndScheduler(void)
{
    /*  关闭中断、调用port层函数结束调度器 */
    portDISABLE_INTERRUPTS();
    xSchedulerRunning = pdFALSE;
    vPortEndScheduler();
}
/*----------------------------------------------------------*/
//挂起任务调度器
void vTaskSuspendAll(void)
{
    /* A critical section is not required as the variable is of type
     * BaseType_t.  Please read Richard Barry's reply in the following link to a
     * post in the FreeRTOS support forum before reporting this as a bug! -
     * https://goo.gl/wu4acr */

    /* portSOFRWARE_BARRIER() is only implemented for emulated/simulated ports that
     * do not otherwise exhibit real time behaviour. */
    portSOFTWARE_BARRIER();

    //uxSchedulerSuspended不为0时、调度器挂起
    ++uxSchedulerSuspended;

    /* Enforces ordering for ports and optimised compilers that may otherwise place
     * the above increment elsewhere. */
    portMEMORY_BARRIER();
}
/*----------------------------------------------------------*/

#if (configUSE_TICKLESS_IDLE != 0)

static TickType_t prvGetExpectedIdleTime(void)
{
    TickType_t xReturn;
    UBaseType_t uxHigherPriorityReadyTasks = pdFALSE;

/* uxHigherPriorityReadyTasks takes care of the case where
         * configUSE_PREEMPTION is 0, so there may be tasks above the idle priority
         * task that are in the Ready state, even though the idle task is
         * running. */
#if (configUSE_PORT_OPTIMISED_TASK_SELECTION == 0)
    {
        if (uxTopReadyPriority > tskIDLE_PRIORITY)
        {
            uxHigherPriorityReadyTasks = pdTRUE;
        }
    }
#else
    {
        const UBaseType_t uxLeastSignificantBit = (UBaseType_t)0x01;

        /* When port optimised task selection is used the uxTopReadyPriority
                 * variable is used as a bit map.  If bits other than the least
                 * significant bit are set then there are tasks that have a priority
                 * above the idle priority that are in the Ready state.  This takes
                 * care of the case where the co-operative scheduler is in use. */
        if (uxTopReadyPriority > uxLeastSignificantBit)
        {
            uxHigherPriorityReadyTasks = pdTRUE;
        }
    }
#endif /* if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) */

    if (pxCurrentTCB->uxPriority > tskIDLE_PRIORITY)
    {
        xReturn = 0;
    }
    else if (listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[tskIDLE_PRIORITY])) > 1)
    {
        /* There are other idle priority tasks in the ready state.  If
             * time slicing is used then the very next tick interrupt must be
             * processed. */
        xReturn = 0;
    }
    else if (uxHigherPriorityReadyTasks != pdFALSE)
    {
        /* There are tasks in the Ready state that have a priority above the
             * idle priority.  This path can only be reached if
             * configUSE_PREEMPTION is 0. */
        xReturn = 0;
    }
    else
    {
        xReturn = xNextTaskUnblockTime - xTickCount;
    }

    return xReturn;
}

#endif /* configUSE_TICKLESS_IDLE */
/*----------------------------------------------------------*/
/*
 * 恢复调度器：需要考虑的情况有：
 * 在调度器挂起期间、一些解锁的任务会被缓存在 xPendingReadyList 链表，恢复调度器时，需要先将这些任务插入到对应的就绪链表中，再启动调度器
 * 返回：本函数内是否已产生调度
 */
BaseType_t xTaskResumeAll(void)
{
    TCB_t *pxTCB = NULL;
    BaseType_t xAlreadyYielded = pdFALSE;

    //若uxSchedulerSuspended==0 则xTaskResumeAll与xTaskSuppendAll不是成对出现，不匹配，程序出错
    configASSERT(uxSchedulerSuspended);
    //进入临界区 防止中断修改xPendingReadyList链表
    taskENTER_CRITICAL();
    {
        --uxSchedulerSuspended;
        //uxSchedulerSuspended为0 可以开启调度器
        if (uxSchedulerSuspended == (UBaseType_t)pdFALSE)
        {
            if (uxCurrentNumberOfTasks > (UBaseType_t)0U)
            {
                //遍历将xPendingReadyList中的任务插入对应的就绪链表
                while (listLIST_IS_EMPTY(&xPendingReadyList) == pdFALSE)
                {
                    pxTCB = listGET_OWNER_OF_HEAD_ENTRY((&xPendingReadyList));
                    (void)uxListRemove(&(pxTCB->xEventListItem));
                    (void)uxListRemove(&(pxTCB->xStateListItem));
                    prvAddTaskToReadyList(pxTCB);

                    //插入就绪表的任务优先级高于当前任务优先级 需要调度
                    if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority)
                    {
                        xYieldPending = pdTRUE;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }

                if (pxTCB != NULL)
                {

                    //有至少一个任务解锁成功、重新计算下次唤醒时间
                    prvResetNextTaskUnblockTime();
                }

                //将调度器挂起是错误的时钟节拍xPendedTicks补偿到xTickCount
                {
                    TickType_t xPendedCounts = xPendedTicks; /* Non-volatile copy. */

                    if (xPendedCounts > (TickType_t)0U)
                    {
                        do
                        {
                            if (xTaskIncrementTick() != pdFALSE)
                            {
                                xYieldPending = pdTRUE;
                            }
                            else
                            {
                                mtCOVERAGE_TEST_MARKER();
                            }

                            --xPendedCounts;
                        } while (xPendedCounts > (TickType_t)0U);

                        xPendedTicks = 0; //清零
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                //若有任务调度请求被挂起、则立刻启动一次任务调度
                if (xYieldPending != pdFALSE)
                {

                    {
                        xAlreadyYielded = pdTRUE;
                    }

                    taskYIELD_IF_USING_PREEMPTION();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    taskEXIT_CRITICAL();

    return xAlreadyYielded;
}
/*-----------------------------------------------------------*/

TickType_t xTaskGetTickCount(void)
{
    TickType_t xTicks;

    /*使用16位cpu，读取xTickCount的操作不是原子的 故需要进入临界区，*/
    portTICK_TYPE_ENTER_CRITICAL();
    {
        xTicks = xTickCount;
    }
    portTICK_TYPE_EXIT_CRITICAL();

    return xTicks;
}
/*-----------------------------------------------------------*/

TickType_t xTaskGetTickCountFromISR(void)
{
    TickType_t xReturn;
    UBaseType_t uxSavedInterruptStatus;

    /* RTOS ports that support interrupt nesting have the concept of a maximum
     * system call (or maximum API call) interrupt priority.  Interrupts that are
     * above the maximum system call priority are kept permanently enabled, even
     * when the RTOS kernel is in a critical section, but cannot make any calls to
     * FreeRTOS API functions.  If configASSERT() is defined in FreeRTOSConfig.h
     * then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
     * failure if a FreeRTOS API function is called from an interrupt that has been
     * assigned a priority above the configured maximum system call priority.
     * Only FreeRTOS functions that end in FromISR can be called from interrupts
     * that have been assigned a priority at or (logically) below the maximum
     * system call  interrupt priority.  FreeRTOS maintains a separate interrupt
     * safe API to ensure interrupt entry is as fast and as simple as possible.
     * More information (albeit Cortex-M specific) is provided on the following
     * link: https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
    portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

    uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR();
    {
        xReturn = xTickCount;
    }
    portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);

    return xReturn;
}
/*-----------------------------------------------------------*/

UBaseType_t uxTaskGetNumberOfTasks(void)
{
    /* A critical section is not required because the variables are of type
     * BaseType_t. */
    return uxCurrentNumberOfTasks;
}
/*-----------------------------------------------------------*/

char *pcTaskGetName(TaskHandle_t xTaskToQuery) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
    TCB_t *pxTCB;

    /* If null is passed in here then the name of the calling task is being
     * queried. */
    pxTCB = prvGetTCBFromHandle(xTaskToQuery);
    configASSERT(pxTCB);
    return &(pxTCB->pcTaskName[0]);
}
/*-----------------------------------------------------------*/

#if (INCLUDE_xTaskGetHandle == 1)

static TCB_t *prvSearchForNameWithinSingleList(List_t *pxList,
                                               const char pcNameToQuery[])
{
    TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL;
    UBaseType_t x;
    char cNextChar;
    BaseType_t xBreakLoop;

    /* 在调度器挂起时，调研当前函数 */

    if (listCURRENT_LIST_LENGTH(pxList) > (UBaseType_t)0)
    {
        listGET_OWNER_OF_NEXT_ENTRY(pxFirstTCB, pxList); //获取第一个遍历的tcb、用于判断遍历是否结束

        do
        {
            listGET_OWNER_OF_NEXT_ENTRY(pxNextTCB, pxList);

            xBreakLoop = pdFALSE; //是否跳出循环、不匹配时立刻跳出循环

            for (x = (UBaseType_t)0; x < (UBaseType_t)configMAX_TASK_NAME_LEN; x++)
            {
                cNextChar = pxNextTCB->pcTaskName[x];

                if (cNextChar != pcNameToQuery[x])
                {
                    //字符不匹配跳出循环
                    xBreakLoop = pdTRUE;
                }
                else if (cNextChar == (char)0x00)
                {
                    //字符串结束、匹配成功
                    pxReturn = pxNextTCB;
                    xBreakLoop = pdTRUE;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                if (xBreakLoop != pdFALSE)
                {
                    break;
                }
            }

            if (pxReturn != NULL)
            {
                //任务句柄找到，跳出循环
                break;
            }
        } while (pxNextTCB != pxFirstTCB);
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return pxReturn;
}

#endif /* INCLUDE_xTaskGetHandle */
/*-----------------------------------------------------------*/

#if (INCLUDE_xTaskGetHandle == 1)

TaskHandle_t xTaskGetHandle(const char *pcNameToQuery) 
{
    UBaseType_t uxQueue = configMAX_PRIORITIES; //从最大优先级开始搜索
    TCB_t *pxTCB;

    /* 任务名称长度必须小于 configMAX_TASK_NAME_LEN - 1 bytes. */
    configASSERT(strlen(pcNameToQuery) < configMAX_TASK_NAME_LEN);
    //挂起任务调度器 防止其他任务修改就绪、挂起、延时链表。中断不会修改延时他们，不需要进入临界段
    vTaskSuspendAll();
    {
        /* 搜索所有就绪链表 */
        do
        {
            uxQueue--;
            pxTCB = prvSearchForNameWithinSingleList((List_t *)&(pxReadyTasksLists[uxQueue]), pcNameToQuery);

            if (pxTCB != NULL)
            {
                /* Found the handle. */
                break;
            }
        } while (uxQueue > (UBaseType_t)tskIDLE_PRIORITY); 

        /* 搜索延时链表 */
        if (pxTCB == NULL)
        {
            pxTCB = prvSearchForNameWithinSingleList((List_t *)pxDelayedTaskList, pcNameToQuery);
        }

        if (pxTCB == NULL)
        {
            pxTCB = prvSearchForNameWithinSingleList((List_t *)pxOverflowDelayedTaskList, pcNameToQuery);
        }


        {
            if (pxTCB == NULL)
            {
                /* 搜索挂起链表. */
                pxTCB = prvSearchForNameWithinSingleList(&xSuspendedTaskList, pcNameToQuery);
            }
        }


#if (INCLUDE_vTaskDelete == 1)
        {
            if (pxTCB == NULL)
            {
                /* 搜索删除链表. */
                pxTCB = prvSearchForNameWithinSingleList(&xTasksWaitingTermination, pcNameToQuery);
            }
        }
#endif
    }
    (void)xTaskResumeAll();

    return pxTCB;
}

#endif /* INCLUDE_xTaskGetHandle */
/*-----------------------------------------------------------*/

#if (configUSE_TRACE_FACILITY == 1)

UBaseType_t uxTaskGetSystemState(TaskStatus_t *const pxTaskStatusArray,
                                 const UBaseType_t uxArraySize,
                                 uint32_t *const pulTotalRunTime)
{
    UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
    //挂起任务调度器 防止其他任务修改就绪、挂起、延时链表。中断不会修改延时他们，不需要进入临界段
    vTaskSuspendAll();
    {
        /* uxArraySize必须大于等于当前任务数量，否则pxTaskStatusArray内存不够用 */
        if (uxArraySize >= uxCurrentNumberOfTasks)
        {
            /* 获取就绪链表中的任务信息 */
            do
            {
                uxQueue--;
                uxTask += prvListTasksWithinSingleList(&(pxTaskStatusArray[uxTask]), &(pxReadyTasksLists[uxQueue]), eReady);
            } while (uxQueue > (UBaseType_t)tskIDLE_PRIORITY); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */

            /* 获取延时链表中的任务信息 */
            uxTask += prvListTasksWithinSingleList(&(pxTaskStatusArray[uxTask]), (List_t *)pxDelayedTaskList, eBlocked);
            uxTask += prvListTasksWithinSingleList(&(pxTaskStatusArray[uxTask]), (List_t *)pxOverflowDelayedTaskList, eBlocked);



            {
                /* 获取等待终止链表中的任务信息 */
                uxTask += prvListTasksWithinSingleList(&(pxTaskStatusArray[uxTask]), &xTasksWaitingTermination, eDeleted);
            }



            {
                /* 获取挂起链表中的任务信息 */
                uxTask += prvListTasksWithinSingleList(&(pxTaskStatusArray[uxTask]), &xSuspendedTaskList, eSuspended);
            }


#if (configGENERATE_RUN_TIME_STATS == 1)
            {
                if (pulTotalRunTime != NULL)
                {
#ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
                    portALT_GET_RUN_TIME_COUNTER_VALUE((*pulTotalRunTime));
#else
                    *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
#endif
                }
            }
#else  /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */
            {
                if (pulTotalRunTime != NULL)
                {
                    *pulTotalRunTime = 0;
                }
            }
#endif /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    (void)xTaskResumeAll();

    return uxTask;
}

#endif /* configUSE_TRACE_FACILITY */
/*----------------------------------------------------------*/

#if (INCLUDE_xTaskGetIdleTaskHandle == 1)

TaskHandle_t xTaskGetIdleTaskHandle(void)
{
    /* If xTaskGetIdleTaskHandle() is called before the scheduler has been
         * started, then xIdleTaskHandle will be NULL. */
    configASSERT((xIdleTaskHandle != NULL));
    return xIdleTaskHandle;
}

#endif /* INCLUDE_xTaskGetIdleTaskHandle */
/*----------------------------------------------------------*/

/* This conditional compilation should use inequality to 0, not equality to 1.
 * This is to ensure vTaskStepTick() is available when user defined low power mode
 * implementations require configUSE_TICKLESS_IDLE to be set to a value other than
 * 1. */
#if (configUSE_TICKLESS_IDLE != 0)

void vTaskStepTick(const TickType_t xTicksToJump)
{
    /* Correct the tick count value after a period during which the tick
         * was suppressed.  Note this does *not* call the tick hook function for
         * each stepped tick. */
    configASSERT((xTickCount + xTicksToJump) <= xNextTaskUnblockTime);
    xTickCount += xTicksToJump;
    traceINCREASE_TICK_COUNT(xTicksToJump);
}

#endif /* configUSE_TICKLESS_IDLE */
/*----------------------------------------------------------*/

BaseType_t xTaskCatchUpTicks(TickType_t xTicksToCatchUp)
{
    BaseType_t xYieldOccurred;

    /* Must not be called with the scheduler suspended as the implementation
     * relies on xPendedTicks being wound down to 0 in xTaskResumeAll(). */
    //必须在调度器不挂起时调用.调度器挂起时，错过的时间会已经保存在xPendedTicks中
    configASSERT(uxSchedulerSuspended == 0);

    /* Use xPendedTicks to mimic xTicksToCatchUp number of ticks occurring when
     * the scheduler is suspended so the ticks are executed in xTaskResumeAll(). */
    vTaskSuspendAll();      //这里挂起调度器是为了后面的xTaskResumeAll();能正确的补偿
    xPendedTicks += xTicksToCatchUp;
    xYieldOccurred = xTaskResumeAll();

    return xYieldOccurred;
}
/*----------------------------------------------------------*/



BaseType_t xTaskAbortDelay(TaskHandle_t xTask)
{
    TCB_t *pxTCB = xTask;
    BaseType_t xReturn;

    configASSERT(pxTCB);
    //挂起任务调度器 防止其他任务修改就绪、延时链表
    vTaskSuspendAll();
    {
        //任务的状态为阻塞时，才能解锁
        if (eTaskGetState(xTask) == eBlocked)
        {
            xReturn = pdPASS;

            
            //从延时链表中移除 当调度器挂起时、中断不会修改任务的xStateListItem.所以在这里的操作是安全的
            (void)uxListRemove(&(pxTCB->xStateListItem));

            //从事件链表中移除 （中断可能修改xEventListItem 故需要进入临界区）
            taskENTER_CRITICAL();
            {
                if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL)
                {
                    (void)uxListRemove(&(pxTCB->xEventListItem));
                    //记录他已经解除挂起
                    pxTCB->ucDelayAborted = pdTRUE;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            taskEXIT_CRITICAL();

            //退出延时后，进入就绪态（因为中断中不能访问就绪链表，故当前函数不能在中断中调用）
            prvAddTaskToReadyList(pxTCB);

            {
                //解锁任务的优先级高于当前任务优先级，发生抢占
                if (pxTCB->uxPriority > pxCurrentTCB->uxPriority)
                {
                    //挂起一次任务调度（因为当前调度器挂起了）
                    xYieldPending = pdTRUE;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }

        }
        else
        {
            xReturn = pdFAIL;
        }
    }
    (void)xTaskResumeAll();

    return xReturn;
}


/*----------------------------------------------------------*/

BaseType_t xTaskIncrementTick(void)
{
    TCB_t *pxTCB;
    TickType_t xItemValue;
    BaseType_t xSwitchRequired = pdFALSE;

    /* Called by the portable layer each time a tick interrupt occurs.
     * Increments the tick then checks to see if the new tick value will cause any
     * tasks to be unblocked. */
    traceTASK_INCREMENT_TICK(xTickCount);

    if (uxSchedulerSuspended == (UBaseType_t)pdFALSE)
    {
        /* Minor optimisation.  The tick count cannot change in this
         * block. */
        //todo 先用一个常量的局部变量保存新的时钟计数值，再将常量复制到全局变量
        const TickType_t xConstTickCount = xTickCount + (TickType_t)1;

        xTickCount = xConstTickCount;

        //若计数值溢出、则切换延时链表
        if (xConstTickCount == (TickType_t)0U) 
        {
            taskSWITCH_DELAYED_LISTS();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        //当任务的延时时间值小于等于当前时钟计数值时、说明延时时间到达
        if (xConstTickCount >= xNextTaskUnblockTime)
        {
            for (;;)
            {
                if (listLIST_IS_EMPTY(pxDelayedTaskList) != pdFALSE)
                {

                    //延时链表为空，则设置xNextTaskUnblockTime为最大值，下次进入时就不会检查延时链表
                    xNextTaskUnblockTime = portMAX_DELAY; 
                    break;
                }
                else
                {
                    //延时链表不为空、则获取链表第一个节点的信息
                    pxTCB = listGET_OWNER_OF_HEAD_ENTRY(pxDelayedTaskList);
                    xItemValue = listGET_LIST_ITEM_VALUE(&(pxTCB->xStateListItem));
                    
                    //任务的延时时间值 大于 当前的时钟计数值，还未到解锁时间
                    if (xConstTickCount < xItemValue)
                    {
                        //更新xNextTaskUnblockTime，循环中只要有大于当前时钟计数值的，保存为下次解锁时间并退出循环
                        xNextTaskUnblockTime = xItemValue;
                        break; 
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

                    //来到这，说明任务需要解锁 移出延时何事件链表，添加到就绪链表
                    (void)uxListRemove(&(pxTCB->xStateListItem));


                    if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL)
                    {
                        (void)uxListRemove(&(pxTCB->xEventListItem));
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

                    prvAddTaskToReadyList(pxTCB);

                    {
                        //解锁任务优先级高于当前任务、则需要一次任务调度
                        if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority)
                        {
                            xSwitchRequired = pdTRUE;
                        }
                        else
                        {
                            mtCOVERAGE_TEST_MARKER();
                        }
                    }

                }
            }
        }

        //todo 时间片功能的实现
        {
            if (listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[pxCurrentTCB->uxPriority])) > (UBaseType_t)1)
            {
                xSwitchRequired = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }


#if (configUSE_TICK_HOOK == 1)
        {
            /* Guard against the tick hook being called when the pended tick
                 * count is being unwound (when the scheduler is being unlocked). */
            if (xPendedTicks == (TickType_t)0)
            {
                vApplicationTickHook();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
#endif /* configUSE_TICK_HOOK */

        //todo 
        {
            if (xYieldPending != pdFALSE)
            {
                xSwitchRequired = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }

    }
    else    //调度器挂起了，记录错过的时钟节拍数
    {
        ++xPendedTicks;

/* The tick hook gets called at regular intervals, even if the
         * scheduler is locked. */
#if (configUSE_TICK_HOOK == 1)
        {
            vApplicationTickHook();
        }
#endif
    }

    return xSwitchRequired;
}

/*-----------------------------------------------------------*/

void vTaskSwitchContext(void)
{
    //若任务调度器被挂起、则设置xYieldPending = pdTRUE;表示一个任务调度的请求被挂起、调度器恢复后会立刻执行一次调度
    if (uxSchedulerSuspended != (UBaseType_t)pdFALSE)
    {

        xYieldPending = pdTRUE;
    }
    else
    {
        xYieldPending = pdFALSE;
        traceTASK_SWITCHED_OUT();

#if (configGENERATE_RUN_TIME_STATS == 1)
        {
#ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
            portALT_GET_RUN_TIME_COUNTER_VALUE(ulTotalRunTime);
#else
            ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
#endif

            /* Add the amount of time the task has been running to the
                 * accumulated time so far.  The time the task started running was
                 * stored in ulTaskSwitchedInTime.  Note that there is no overflow
                 * protection here so count values are only valid until the timer
                 * overflows.  The guard against negative values is to protect
                 * against suspect run time stat counter implementations - which
                 * are provided by the application, not the kernel. */
            if (ulTotalRunTime > ulTaskSwitchedInTime)
            {
                pxCurrentTCB->ulRunTimeCounter += (ulTotalRunTime - ulTaskSwitchedInTime);
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            ulTaskSwitchedInTime = ulTotalRunTime;
        }
#endif /* configGENERATE_RUN_TIME_STATS */

        /* Check for stack overflow, if configured. */
        taskCHECK_FOR_STACK_OVERFLOW();

/* Before the currently running task is switched out, save its errno. */
#if (configUSE_POSIX_ERRNO == 1)
        {
            pxCurrentTCB->iTaskErrno = FreeRTOS_errno;
        }
#endif

        //选择最高优先级任务 更新到pxCurrentTCB
        taskSELECT_HIGHEST_PRIORITY_TASK();
        traceTASK_SWITCHED_IN();

/* After the new task is switched in, update the global errno. */
#if (configUSE_POSIX_ERRNO == 1)
        {
            FreeRTOS_errno = pxCurrentTCB->iTaskErrno;
        }
#endif

#if (configUSE_NEWLIB_REENTRANT == 1)
        {
            /* Switch Newlib's _impure_ptr variable to point to the _reent
                 * structure specific to this task.
                 * See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
                 * for additional information. */
            _impure_ptr = &(pxCurrentTCB->xNewLib_reent);
        }
#endif /* configUSE_NEWLIB_REENTRANT */
    }
}
/*-----------------------------------------------------------*/

void vTaskPlaceOnEventList(List_t *const pxEventList,
                           const TickType_t xTicksToWait)
{
    configASSERT(pxEventList);

    /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE
     * SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */

    /* Place the event list item of the TCB in the appropriate event list.
     * This is placed in the list in priority order so the highest priority task
     * is the first to be woken by the event.  The queue that contains the event
     * list is locked, preventing simultaneous access from interrupts. */
    vListInsert(pxEventList, &(pxCurrentTCB->xEventListItem));

    prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE);
}
/*-----------------------------------------------------------*/

void vTaskPlaceOnUnorderedEventList(List_t *pxEventList,
                                    const TickType_t xItemValue,
                                    const TickType_t xTicksToWait)
{
    configASSERT(pxEventList);

    /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED.  It is used by
     * the event groups implementation. */
    configASSERT(uxSchedulerSuspended != 0);

    /* Store the item value in the event list item.  It is safe to access the
     * event list item here as interrupts won't access the event list item of a
     * task that is not in the Blocked state. */
    //设置新的事件节点的值
    listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xEventListItem), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE);

    /* Place the event list item of the TCB at the end of the appropriate event
     * list.  It is safe to access the event list here because it is part of an
     * event group implementation - and interrupts don't access event groups
     * directly (instead they access them indirectly by pending function calls to
     * the task level). */
    vListInsertEnd(pxEventList, &(pxCurrentTCB->xEventListItem));

    prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE);
}
/*-----------------------------------------------------------*/

#if (configUSE_TIMERS == 1)

void vTaskPlaceOnEventListRestricted(List_t *const pxEventList,
                                     TickType_t xTicksToWait,
                                     const BaseType_t xWaitIndefinitely)
{
    configASSERT(pxEventList);

    /* This function should not be called by application code hence the
         * 'Restricted' in its name.  It is not part of the public API.  It is
         * designed for use by kernel code, and has special calling requirements -
         * it should be called with the scheduler suspended. */

    /* Place the event list item of the TCB in the appropriate event list.
         * In this case it is assume that this is the only task that is going to
         * be waiting on this event list, so the faster vListInsertEnd() function
         * can be used in place of vListInsert. */
    vListInsertEnd(pxEventList, &(pxCurrentTCB->xEventListItem));

    /* If the task should block indefinitely then set the block time to a
         * value that will be recognised as an indefinite delay inside the
         * prvAddCurrentTaskToDelayedList() function. */
    if (xWaitIndefinitely != pdFALSE)
    {
        xTicksToWait = portMAX_DELAY;
    }

    traceTASK_DELAY_UNTIL((xTickCount + xTicksToWait));
    prvAddCurrentTaskToDelayedList(xTicksToWait, xWaitIndefinitely);
}

#endif /* configUSE_TIMERS */
/*-----------------------------------------------------------*/

BaseType_t xTaskRemoveFromEventList(const List_t *const pxEventList)
{
    TCB_t *pxUnblockedTCB;
    BaseType_t xReturn;

    /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION.  It can also be
     * called from a critical section within an ISR. */

    /* The event list is sorted in priority order, so the first in the list can
     * be removed as it is known to be the highest priority.  Remove the TCB from
     * the delayed list, and add it to the ready list.
     *
     * If an event is for a queue that is locked then this function will never
     * get called - the lock count on the queue will get modified instead.  This
     * means exclusive access to the event list is guaranteed here.
     *
     * This function assumes that a check has already been made to ensure that
     * pxEventList is not empty. */
    //获取事件链表的第一个任务
    pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY(pxEventList); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
    configASSERT(pxUnblockedTCB);
    //移除链表
    (void)uxListRemove(&(pxUnblockedTCB->xEventListItem));

    //调度器正在运行
    if (uxSchedulerSuspended == (UBaseType_t)pdFALSE)
    {
        //移动到就绪链表
        (void)uxListRemove(&(pxUnblockedTCB->xStateListItem));
        prvAddTaskToReadyList(pxUnblockedTCB);

#if (configUSE_TICKLESS_IDLE != 0)
        {
            /* If a task is blocked on a kernel object then xNextTaskUnblockTime
                 * might be set to the blocked task's time out time.  If the task is
                 * unblocked for a reason other than a timeout xNextTaskUnblockTime is
                 * normally left unchanged, because it is automatically reset to a new
                 * value when the tick count equals xNextTaskUnblockTime.  However if
                 * tickless idling is used it might be more important to enter sleep mode
                 * at the earliest possible time - so reset xNextTaskUnblockTime here to
                 * ensure it is updated at the earliest possible time. */
            prvResetNextTaskUnblockTime();
        }
#endif
    }
    else
    {
        //调度器挂起、就绪链表不能访问，暂时插到xPendingReadyList链表
        vListInsertEnd(&(xPendingReadyList), &(pxUnblockedTCB->xEventListItem));
    }

    if (pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority)
    {
        //因为可以在中断执行，所以不能直接进行任务调度而是通过返回值，让函数调用者来产生任务调度
        //返回真 使调用者在退出后执行一次任务调度
        xReturn = pdTRUE;

        //标记、以防调用者忘记调度
        xYieldPending = pdTRUE;
    }
    else
    {
        xReturn = pdFALSE;
    }

    return xReturn;
}
/*-----------------------------------------------------------*/

void vTaskRemoveFromUnorderedEventList(ListItem_t *pxEventListItem,
                                       const TickType_t xItemValue)
{
    TCB_t *pxUnblockedTCB;

    /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED.  It is used by
     * the event flags implementation. */
    //该函数必须挂起调度器 他用于实现事件标志
    configASSERT(uxSchedulerSuspended != pdFALSE);

    /* Store the new item value in the event list. */
    //更新事件节点的值
    listSET_LIST_ITEM_VALUE(pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE);

    /* Remove the event list form the event flag.  Interrupts do not access
     * event flags. */
    //将任务移出事件链表
    pxUnblockedTCB = listGET_LIST_ITEM_OWNER(pxEventListItem); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
    configASSERT(pxUnblockedTCB);
    (void)uxListRemove(pxEventListItem);

#if (configUSE_TICKLESS_IDLE != 0)
    {
        /* If a task is blocked on a kernel object then xNextTaskUnblockTime
             * might be set to the blocked task's time out time.  If the task is
             * unblocked for a reason other than a timeout xNextTaskUnblockTime is
             * normally left unchanged, because it is automatically reset to a new
             * value when the tick count equals xNextTaskUnblockTime.  However if
             * tickless idling is used it might be more important to enter sleep mode
             * at the earliest possible time - so reset xNextTaskUnblockTime here to
             * ensure it is updated at the earliest possible time. */
        prvResetNextTaskUnblockTime();
    }
#endif

    /* Remove the task from the delayed list and add it to the ready list.  The
     * scheduler is suspended so interrupts will not be accessing the ready
     * lists. */
    //将任务移动到就绪链表 调度器被挂起故中断不会修改就绪链表，所以这里是安全的
    (void)uxListRemove(&(pxUnblockedTCB->xStateListItem));
    prvAddTaskToReadyList(pxUnblockedTCB);

    if (pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority)
    {
        //优先级高，发送抢占，但调度器被挂起，故设置xYieldPending为真
        xYieldPending = pdTRUE;
    }
}
/*-----------------------------------------------------------*/

void vTaskSetTimeOutState(TimeOut_t *const pxTimeOut)
{
    configASSERT(pxTimeOut);

    taskENTER_CRITICAL();
    {
        pxTimeOut->xOverflowCount = xNumOfOverflows;
        pxTimeOut->xTimeOnEntering = xTickCount;
    }
    taskEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/

void vTaskInternalSetTimeOutState(TimeOut_t *const pxTimeOut)
{
    /* 在临界区内调用，故不需要临界段保护. */
    pxTimeOut->xOverflowCount = xNumOfOverflows;
    pxTimeOut->xTimeOnEntering = xTickCount;
}
/*-----------------------------------------------------------*/

BaseType_t xTaskCheckForTimeOut(TimeOut_t *const pxTimeOut,
                                TickType_t *const pxTicksToWait)
{
    BaseType_t xReturn;

    configASSERT(pxTimeOut);
    configASSERT(pxTicksToWait);

    taskENTER_CRITICAL();
    {
        /* Minor optimisation.  The tick count cannot change in this block. */
        const TickType_t xConstTickCount = xTickCount;
        const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering;

#if (INCLUDE_xTaskAbortDelay == 1)
        if (pxCurrentTCB->ucDelayAborted != (uint8_t)pdFALSE)
        {
            /* The delay was aborted, which is not the same as a time out,
                 * but has the same result. */
            pxCurrentTCB->ucDelayAborted = pdFALSE;
            xReturn = pdTRUE;
        }
        else
#endif


            if (*pxTicksToWait == portMAX_DELAY)
        {
            /* If INCLUDE_vTaskSuspend is set to 1 and the block time
                 * specified is the maximum block time then the task should block
                 * indefinitely, and therefore never time out. */
            xReturn = pdFALSE;
        }
        else


            if ((xNumOfOverflows != pxTimeOut->xOverflowCount) && (xConstTickCount >= pxTimeOut->xTimeOnEntering)) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */
        {
            /* The tick count is greater than the time at which
             * vTaskSetTimeout() was called, but has also overflowed since
             * vTaskSetTimeOut() was called.  It must have wrapped all the way
             * around and gone past again. This passed since vTaskSetTimeout()
             * was called. */
            xReturn = pdTRUE;
            *pxTicksToWait = (TickType_t)0;
        }
        else if (xElapsedTime < *pxTicksToWait) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
        {
            /* Not a genuine timeout. Adjust parameters for time remaining. */
            *pxTicksToWait -= xElapsedTime;
            vTaskInternalSetTimeOutState(pxTimeOut);
            xReturn = pdFALSE;
        }
        else
        {
            *pxTicksToWait = (TickType_t)0;
            xReturn = pdTRUE;
        }
    }
    taskEXIT_CRITICAL();

    return xReturn;
}
/*-----------------------------------------------------------*/

void vTaskMissedYield(void)
{
    xYieldPending = pdTRUE;
}
/*-----------------------------------------------------------*/

#if (configUSE_TRACE_FACILITY == 1)

UBaseType_t uxTaskGetTaskNumber(TaskHandle_t xTask)
{
    UBaseType_t uxReturn;
    TCB_t const *pxTCB;

    if (xTask != NULL)
    {
        pxTCB = xTask;
        uxReturn = pxTCB->uxTaskNumber;
    }
    else
    {
        uxReturn = 0U;
    }

    return uxReturn;
}

#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/

#if (configUSE_TRACE_FACILITY == 1)

void vTaskSetTaskNumber(TaskHandle_t xTask,
                        const UBaseType_t uxHandle)
{
    TCB_t *pxTCB;

    if (xTask != NULL)
    {
        pxTCB = xTask;
        pxTCB->uxTaskNumber = uxHandle;
    }
}

#endif /* configUSE_TRACE_FACILITY */

/*
 * -----------------------------------------------------------
 * 空闲任务 主要负责释放内存
 * ----------------------------------------------------------
 *
 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
 * language extensions.  The equivalent prototype for this function is:
 *
 * void prvIdleTask( void *pvParameters );
 *
 */
static portTASK_FUNCTION(prvIdleTask, pvParameters)
{
    /* Stop warnings. */
    (void)pvParameters;



    /* In case a task that has a secure context deletes itself, in which case
     * the idle task is responsible for deleting the task's secure context, if
     * any. */
    portALLOCATE_SECURE_CONTEXT(configMINIMAL_SECURE_STACK_SIZE);

    for (;;)
    {
        //释放僵尸任务
        prvCheckTasksWaitingTermination();

#if (configUSE_PREEMPTION == 0)
        {
            //进行一次任务调度
            taskYIELD();
        }
#endif /* configUSE_PREEMPTION */

#if ((configUSE_PREEMPTION == 1) && (configIDLE_SHOULD_YIELD == 1))
        {
            /* When using preemption tasks of equal priority will be
                 * timesliced.  If a task that is sharing the idle priority is ready
                 * to run then the idle task should yield before the end of the
                 * timeslice.
                 *
                 * A critical region is not required here as we are just reading from
                 * the list, and an occasional incorrect value will not matter.  If
                 * the ready list at the idle priority contains more than one task
                 * then a task other than the idle task is ready to execute. */
            //在使用时间片的情况下，若用户任务的优先级与空闲任务一样，且已经就绪 则切换到该任务执行
            if (listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[tskIDLE_PRIORITY])) > (UBaseType_t)1)
            {
                taskYIELD();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */

#if (configUSE_IDLE_HOOK == 1)
        {
            extern void vApplicationIdleHook(void);

            /* Call the user defined function from within the idle task.  This
                 * allows the application designer to add background functionality
                 * without the overhead of a separate task.
                 * NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
                 * CALL A FUNCTION THAT MIGHT BLOCK. */
            //调用用户的空闲回调函数
            vApplicationIdleHook();
        }
#endif /* configUSE_IDLE_HOOK */

/* This conditional compilation should use inequality to 0, not equality
         * to 1.  This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
         * user defined low power mode  implementations require
         * configUSE_TICKLESS_IDLE to be set to a value other than 1. */
#if (configUSE_TICKLESS_IDLE != 0)
        {
            TickType_t xExpectedIdleTime;

            /* It is not desirable to suspend then resume the scheduler on
                 * each iteration of the idle task.  Therefore, a preliminary
                 * test of the expected idle time is performed without the
                 * scheduler suspended.  The result here is not necessarily
                 * valid. */
            xExpectedIdleTime = prvGetExpectedIdleTime();

            if (xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP)
            {
                vTaskSuspendAll();
                {
                    /* Now the scheduler is suspended, the expected idle
                         * time can be sampled again, and this time its value can
                         * be used. */
                    configASSERT(xNextTaskUnblockTime >= xTickCount);
                    xExpectedIdleTime = prvGetExpectedIdleTime();

                    /* Define the following macro to set xExpectedIdleTime to 0
                         * if the application does not want
                         * portSUPPRESS_TICKS_AND_SLEEP() to be called. */
                    configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING(xExpectedIdleTime);

                    if (xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP)
                    {
                        traceLOW_POWER_IDLE_BEGIN();
                        portSUPPRESS_TICKS_AND_SLEEP(xExpectedIdleTime);
                        traceLOW_POWER_IDLE_END();
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                (void)xTaskResumeAll();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
#endif /* configUSE_TICKLESS_IDLE */
    }
}
/*-----------------------------------------------------------*/

#if (configUSE_TICKLESS_IDLE != 0)

eSleepModeStatus eTaskConfirmSleepModeStatus(void)
{
    /* The idle task exists in addition to the application tasks. */
    const UBaseType_t uxNonApplicationTasks = 1;
    eSleepModeStatus eReturn = eStandardSleep;

    /* This function must be called from a critical section. */

    if (listCURRENT_LIST_LENGTH(&xPendingReadyList) != 0)
    {
        /* A task was made ready while the scheduler was suspended. */
        eReturn = eAbortSleep;
    }
    else if (xYieldPending != pdFALSE)
    {
        /* A yield was pended while the scheduler was suspended. */
        eReturn = eAbortSleep;
    }
    else if (xPendedTicks != 0)
    {
        /* A tick interrupt has already occurred but was held pending
             * because the scheduler is suspended. */
        eReturn = eAbortSleep;
    }
    else
    {
        /* If all the tasks are in the suspended list (which might mean they
             * have an infinite block time rather than actually being suspended)
             * then it is safe to turn all clocks off and just wait for external
             * interrupts. */
        if (listCURRENT_LIST_LENGTH(&xSuspendedTaskList) == (uxCurrentNumberOfTasks - uxNonApplicationTasks))
        {
            eReturn = eNoTasksWaitingTimeout;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

    return eReturn;
}

#endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/

static void prvInitialiseTaskLists(void)
{
    UBaseType_t uxPriority;
    //初始化就绪链表数组
    for (uxPriority = (UBaseType_t)0U; uxPriority < (UBaseType_t)configMAX_PRIORITIES; uxPriority++)
    {
        vListInitialise(&(pxReadyTasksLists[uxPriority]));
    }
    //初始化延时、等待就绪等链表
    vListInitialise(&xDelayedTaskList1);
    vListInitialise(&xDelayedTaskList2);
    vListInitialise(&xPendingReadyList);

#if (INCLUDE_vTaskDelete == 1)
    {
        vListInitialise(&xTasksWaitingTermination);
    }
#endif /* INCLUDE_vTaskDelete */


    {
        vListInitialise(&xSuspendedTaskList);
    }


    /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
     * using list2. */
    pxDelayedTaskList = &xDelayedTaskList1;
    pxOverflowDelayedTaskList = &xDelayedTaskList2;
}
/*-----------------------------------------------------------*/

static void prvCheckTasksWaitingTermination(void)
{

#if (INCLUDE_vTaskDelete == 1)
    {
        TCB_t *pxTCB;

        /* 检查是否有任务需要释放内存*/
        while (uxDeletedTasksWaitingCleanUp > (UBaseType_t)0U)
        {
            //进入临界区 移出链表
            taskENTER_CRITICAL();
            {
                pxTCB = listGET_OWNER_OF_HEAD_ENTRY((&xTasksWaitingTermination)); //获取需要删除的任务
                (void)uxListRemove(&(pxTCB->xStateListItem));
                --uxCurrentNumberOfTasks;
                --uxDeletedTasksWaitingCleanUp;
            }
            taskEXIT_CRITICAL();

            prvDeleteTCB(pxTCB);
        }
    }
#endif /* INCLUDE_vTaskDelete */
}
/*-----------------------------------------------------------*/

#if (configUSE_TRACE_FACILITY == 1)

void vTaskGetInfo(TaskHandle_t xTask,
                  TaskStatus_t *pxTaskStatus,
                  BaseType_t xGetFreeStackSpace,
                  eTaskState eState)
{
    TCB_t *pxTCB;

    //获取tcb
    pxTCB = prvGetTCBFromHandle(xTask);

    //返回tcb里的信息
    pxTaskStatus->xHandle = (TaskHandle_t)pxTCB;
    pxTaskStatus->pcTaskName = (const char *)&(pxTCB->pcTaskName[0]);
    pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority;
    pxTaskStatus->pxStackBase = pxTCB->pxStack;
    pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;


    {
        pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
    }


#if (configGENERATE_RUN_TIME_STATS == 1)
    {
        pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter;
    }
#else
    {
        pxTaskStatus->ulRunTimeCounter = 0;
    }
#endif

    //eState ！= eInvalid 时 快速返回任务状态
    if (eState != eInvalid)
    {
        if (pxTCB == pxCurrentTCB)
        {
            pxTaskStatus->eCurrentState = eRunning;
        }
        else
        {
            pxTaskStatus->eCurrentState = eState;


            {
                /* If the task is in the suspended list then there is a
                         *  chance it is actually just blocked indefinitely - so really
                         *  it should be reported as being in the Blocked state. */
                if (eState == eSuspended)
                {
                    //todo 看不懂为何挂起调度器
                    vTaskSuspendAll();
                    {
                        if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL)
                        {
                            pxTaskStatus->eCurrentState = eBlocked;
                        }
                    }
                    (void)xTaskResumeAll();
                }
            }

        }
    }
    else //eState == eInvalid 时，读取真实的任务状态
    {
        pxTaskStatus->eCurrentState = eTaskGetState(pxTCB);
    }

    //xGetFreeStackSpace == true 时计算栈剩余空间
    if (xGetFreeStackSpace != pdFALSE)
    {
//区别栈的生长方向
#if (portSTACK_GROWTH > 0)
        {
            pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace((uint8_t *)pxTCB->pxEndOfStack);
        }
#else
        {
            pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace((uint8_t *)pxTCB->pxStack);
        }
#endif
    }
    else
    {
        pxTaskStatus->usStackHighWaterMark = 0;
    }
}

#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/

#if (configUSE_TRACE_FACILITY == 1)

static UBaseType_t prvListTasksWithinSingleList(TaskStatus_t *pxTaskStatusArray,
                                                List_t *pxList,
                                                eTaskState eState)
{
    configLIST_VOLATILE TCB_t *pxNextTCB, *pxFirstTCB;
    UBaseType_t uxTask = 0;

    if (listCURRENT_LIST_LENGTH(pxList) > (UBaseType_t)0)
    {
        listGET_OWNER_OF_NEXT_ENTRY(pxFirstTCB, pxList); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */

        /* Populate an TaskStatus_t structure within the
             * pxTaskStatusArray array for each task that is referenced from
             * pxList.  See the definition of TaskStatus_t in task.h for the
             * meaning of each TaskStatus_t structure member. */
        do
        {
            listGET_OWNER_OF_NEXT_ENTRY(pxNextTCB, pxList); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
            vTaskGetInfo((TaskHandle_t)pxNextTCB, &(pxTaskStatusArray[uxTask]), pdTRUE, eState);
            uxTask++;
        } while (pxNextTCB != pxFirstTCB);
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return uxTask;
}

#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/

#if ((configUSE_TRACE_FACILITY == 1) || (INCLUDE_uxTaskGetStackHighWaterMark == 1) || (INCLUDE_uxTaskGetStackHighWaterMark2 == 1))

static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace(const uint8_t *pucStackByte)
{
    uint32_t ulCount = 0U;
    //利用tskSTACK_FILL_BYTE计算剩余栈大小、栈在初始化时其内容全部填充为tskSTACK_FILL_BYTE，若栈的内容为tskSTACK_FILL_BYTE则说明未被使用
    while (*pucStackByte == (uint8_t)tskSTACK_FILL_BYTE)
    {
        pucStackByte -= portSTACK_GROWTH;
        ulCount++;
    }
    //最后得到的是使用的字节空间
    ulCount /= (uint32_t)sizeof(StackType_t);

    return (configSTACK_DEPTH_TYPE)ulCount;
}

#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) */
/*-----------------------------------------------------------*/

#if (INCLUDE_uxTaskGetStackHighWaterMark2 == 1)

/* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are the
 * same except for their return type.  Using configSTACK_DEPTH_TYPE allows the
 * user to determine the return type.  It gets around the problem of the value
 * overflowing on 8-bit types without breaking backward compatibility for
 * applications that expect an 8-bit return type. */
configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2(TaskHandle_t xTask)
{
    TCB_t *pxTCB;
    uint8_t *pucEndOfStack;
    configSTACK_DEPTH_TYPE uxReturn;

    /* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are
         * the same except for their return type.  Using configSTACK_DEPTH_TYPE
         * allows the user to determine the return type.  It gets around the
         * problem of the value overflowing on 8-bit types without breaking
         * backward compatibility for applications that expect an 8-bit return
         * type. */

    pxTCB = prvGetTCBFromHandle(xTask);

#if portSTACK_GROWTH < 0
    {
        pucEndOfStack = (uint8_t *)pxTCB->pxStack;
    }
#else
    {
        pucEndOfStack = (uint8_t *)pxTCB->pxEndOfStack;
    }
#endif

    uxReturn = prvTaskCheckFreeStackSpace(pucEndOfStack);

    return uxReturn;
}

#endif /* INCLUDE_uxTaskGetStackHighWaterMark2 */
/*-----------------------------------------------------------*/

#if (INCLUDE_uxTaskGetStackHighWaterMark == 1)

UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask)
{
    TCB_t *pxTCB;
    uint8_t *pucEndOfStack;
    UBaseType_t uxReturn;

    pxTCB = prvGetTCBFromHandle(xTask);

#if portSTACK_GROWTH < 0
    {
        pucEndOfStack = (uint8_t *)pxTCB->pxStack;
    }
#else
    {
        pucEndOfStack = (uint8_t *)pxTCB->pxEndOfStack;
    }
#endif

    uxReturn = (UBaseType_t)prvTaskCheckFreeStackSpace(pucEndOfStack);

    return uxReturn;
}

#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
/*-----------------------------------------------------------*/
/*
 * 释放TCB、堆栈的内存
 */
static void prvDeleteTCB(TCB_t *pxTCB)
{
    /* This call is required specifically for the TriCore port.  It must be
         * above the vPortFree() calls.  The call is also used by ports/demos that
         * want to allocate and clean RAM statically. */
    portCLEAN_UP_TCB(pxTCB);

/* Free up the memory allocated by the scheduler for the task.  It is up
         * to the task to free any memory allocated at the application level.
         * See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
         * for additional information. */
#if (configUSE_NEWLIB_REENTRANT == 1)
    {
        _reclaim_reent(&(pxTCB->xNewLib_reent));
    }
#endif /* configUSE_NEWLIB_REENTRANT */

#if ((configSUPPORT_DYNAMIC_ALLOCATION == 1) && (configSUPPORT_STATIC_ALLOCATION == 0))
    {
        //任务使用动态内存分配策略，直接释放任务控制块内存、堆栈内存
        vPortFree(pxTCB->pxStack);
        vPortFree(pxTCB);
    }
#elif (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0)
    {
        /* The task could have been allocated statically or dynamically, so
                 * check what was statically allocated before trying to free the
                 * memory. */
        if (pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB)
        {
            //tcb和堆栈都是动态内存分配的，所以必须释放
            vPortFree(pxTCB->pxStack);
            vPortFree(pxTCB);
        }
        else if (pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY)
        {

            vPortFree(pxTCB);
        }
        else
        {
            //tcb和堆栈都是静态内存分配的 不必释放
            configASSERT(pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB);
            mtCOVERAGE_TEST_MARKER();
        }
    }
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
}

/*-----------------------------------------------------------*/

//更新xNextTaskUnblockTime
static void prvResetNextTaskUnblockTime(void)
{
    if (listLIST_IS_EMPTY(pxDelayedTaskList) != pdFALSE)
    {
        //延时链表为空，更新xNextTaskUnblockTime为最大，不会产生调度
        xNextTaskUnblockTime = portMAX_DELAY;
    }
    else
    {
        //延时链表不为空，更新xNextTaskUnblockTime为链表第一个节点的值，即延时时间
        xNextTaskUnblockTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxDelayedTaskList);
    }
}
/*-----------------------------------------------------------*/

#if ((INCLUDE_xTaskGetCurrentTaskHandle == 1) || (configUSE_MUTEXES == 1))

TaskHandle_t xTaskGetCurrentTaskHandle(void)
{
    TaskHandle_t xReturn;

    /* A critical section is not required as this is not called from
         * an interrupt and the current TCB will always be the same for any
         * individual execution thread. */
    xReturn = pxCurrentTCB;

    return xReturn;
}

#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
/*-----------------------------------------------------------*/

#if ((INCLUDE_xTaskGetSchedulerState == 1) || (configUSE_TIMERS == 1))

BaseType_t xTaskGetSchedulerState(void)
{
    BaseType_t xReturn;

    if (xSchedulerRunning == pdFALSE)
    {
        xReturn = taskSCHEDULER_NOT_STARTED;
    }
    else
    {
        if (uxSchedulerSuspended == (UBaseType_t)pdFALSE)
        {
            xReturn = taskSCHEDULER_RUNNING;
        }
        else
        {
            xReturn = taskSCHEDULER_SUSPENDED;
        }
    }

    return xReturn;
}

#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */
/*-----------------------------------------------------------*/



BaseType_t xTaskPriorityInherit(TaskHandle_t const pxMutexHolder)
{
    TCB_t *const pxMutexHolderTCB = pxMutexHolder;  //获取锁的拥有者
    BaseType_t xReturn = pdFALSE;   //返回值表示是否发送继承

    /* If the mutex was given back by an interrupt while the queue was
         * locked then the mutex holder might now be NULL.  _RB_ Is this still
         * needed as interrupts can no longer use mutexes? */
    if (pxMutexHolder != NULL)
    {
        /* If the holder of the mutex has a priority below the priority of
             * the task attempting to obtain the mutex then it will temporarily
             * inherit the priority of the task attempting to obtain the mutex. */
        //拥有锁的任务优先级低于当前（请求获取信号量）任务的优先级 需要继承优先级
        if (pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority)
        {
            /* Adjust the mutex holder state to account for its new
                 * priority.  Only reset the event list item value if the value is
                 * not being used for anything else. */
            //若拥有锁的任务 所在的事件链表是按优先级排序的，则需要修改事件节点的值
            if ((listGET_LIST_ITEM_VALUE(&(pxMutexHolderTCB->xEventListItem)) & taskEVENT_LIST_ITEM_VALUE_IN_USE) == 0UL)
            {
                //设置节点的值为新的优先级
                listSET_LIST_ITEM_VALUE(&(pxMutexHolderTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)pxCurrentTCB->uxPriority); 
            }
            else
            {
                //否则什么也不做
                mtCOVERAGE_TEST_MARKER();
            }

            /* If the task being modified is in the ready state it will need
                 * to be moved into a new list. */
            //若拥有锁的任务是在就绪链表中，则需要将其移动到新的优先级的就绪链表
            if (listIS_CONTAINED_WITHIN(&(pxReadyTasksLists[pxMutexHolderTCB->uxPriority]), &(pxMutexHolderTCB->xStateListItem)) != pdFALSE)
            {
                if (uxListRemove(&(pxMutexHolderTCB->xStateListItem)) == (UBaseType_t)0)
                {
                    /* It is known that the task is in its ready list so
                         * there is no need to check again and the port level
                         * reset macro can be called directly. */
                    portRESET_READY_PRIORITY(pxMutexHolderTCB->uxPriority, uxTopReadyPriority);
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                /* Inherit the priority before being moved into the new list. */
                //继承当前任务优先级 加入就绪链表
                pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
                prvAddTaskToReadyList(pxMutexHolderTCB);
            }
            else
            {
                /* Just inherit the priority. */
                //拥有锁的任务不在就绪链表中，只需要继承当前任务优先级
                pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
            }

            traceTASK_PRIORITY_INHERIT(pxMutexHolderTCB, pxCurrentTCB->uxPriority);

            /* Inheritance occurred. */
            //优先级继承发送
            xReturn = pdTRUE;
        }
        else
        {
            //拥有锁的任务高于当前任务的优先级，但上一次优先级小于当前任务，说明该任务之前被提升了一次优先级
            if (pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority)
            {
                /* The base priority of the mutex holder is lower than the
                     * priority of the task attempting to take the mutex, but the
                     * current priority of the mutex holder is not lower than the
                     * priority of the task attempting to take the mutex.
                     * Therefore the mutex holder must have already inherited a
                     * priority, but inheritance would have occurred if that had
                     * not been the case. */
                //标记优先级反转
                xReturn = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return xReturn;
}


/*-----------------------------------------------------------*/


BaseType_t xTaskPriorityDisinherit(TaskHandle_t const pxMutexHolder)
{
    TCB_t *const pxTCB = pxMutexHolder;
    BaseType_t xReturn = pdFALSE;   //返回真，需要任务调度

    if (pxMutexHolder != NULL)
    {
        /* A task can only have an inherited priority if it holds the mutex.
             * If the mutex is held by a task then it cannot be given from an
             * interrupt, and if a mutex is given by the holding task then it must
             * be the running state task. */
        configASSERT(pxTCB == pxCurrentTCB);
        configASSERT(pxTCB->uxMutexesHeld); //必须拥有锁
        (pxTCB->uxMutexesHeld)--;   //拥有互斥信号的数量-1

        /* Has the holder of the mutex inherited the priority of another
             * task? */
        //优先级不同则出现了优先级反转
        if (pxTCB->uxPriority != pxTCB->uxBasePriority)
        {
            //当不持有互斥信号时才能恢复任务优先级
            if (pxTCB->uxMutexesHeld == (UBaseType_t)0)
            {
                /* A task can only have an inherited priority if it holds
                     * the mutex.  If the mutex is held by a task then it cannot be
                     * given from an interrupt, and if a mutex is given by the
                     * holding task then it must be the running state task.  Remove
                     * the holding task from the ready list. */
                //移出就绪链表
                if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0)
                {
                    portRESET_READY_PRIORITY(pxTCB->uxPriority, uxTopReadyPriority);
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                /* Disinherit the priority before adding the task into the
                     * new  ready list. */
                traceTASK_PRIORITY_DISINHERIT(pxTCB, pxTCB->uxBasePriority);
                //恢复优先级
                pxTCB->uxPriority = pxTCB->uxBasePriority;

                /* Reset the event list item value.  It cannot be in use for
                     * any other purpose if this task is running, and it must be
                     * running to give back the mutex. */
                //设置事件节点的值
                listSET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)pxTCB->uxPriority); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
                //添加到新的就绪表
                prvAddTaskToReadyList(pxTCB);

                /* Return true to indicate that a context switch is required.
                     * This is only actually required in the corner case whereby
                     * multiple mutexes were held and the mutexes were given back
                     * in an order different to that in which they were taken.
                     * If a context switch did not occur when the first mutex was
                     * returned, even if a task was waiting on it, then a context
                     * switch should occur when the last mutex is returned whether
                     * a task is waiting on it or not. */
                //todo 返回真使任务调度
                xReturn = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return xReturn;
}


/*-----------------------------------------------------------*/



void vTaskPriorityDisinheritAfterTimeout(TaskHandle_t const pxMutexHolder,
                                         UBaseType_t uxHighestPriorityWaitingTask)
{
    TCB_t *const pxTCB = pxMutexHolder;
    UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse; 
    const UBaseType_t uxOnlyOneMutexHeld = (UBaseType_t)1;

    if (pxMutexHolder != NULL)
    {
        /* If pxMutexHolder is not NULL then the holder must hold at least
             * one mutex. */
        configASSERT(pxTCB->uxMutexesHeld); //必须拥有锁

        /* Determine the priority to which the priority of the task that
             * holds the mutex should be set.  This will be the greater of the
             * holding task's base priority and the priority of the highest
             * priority task that is waiting to obtain the mutex. */
        //uxPriorityToUse是新的优先级。新的优先级应该是等待锁的任务中优先级最高的那个，这样才能保证最高优先级的任务能在锁释放后第一时间得到运行
        if (pxTCB->uxBasePriority < uxHighestPriorityWaitingTask)
        {
            uxPriorityToUse = uxHighestPriorityWaitingTask;
        }
        else
        {
            uxPriorityToUse = pxTCB->uxBasePriority;
        }

        /* Does the priority need to change? */
        //优先级需要修改
        if (pxTCB->uxPriority != uxPriorityToUse)
        {
            /* Only disinherit if no other mutexes are held.  This is a
                 * simplification in the priority inheritance implementation.  If
                 * the task that holds the mutex is also holding other mutexes then
                 * the other mutexes may have caused the priority inheritance. */
            if (pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld)
            {
                /* If a task has timed out because it already holds the
                     * mutex it was trying to obtain then it cannot of inherited
                     * its own priority. */
                configASSERT(pxTCB != pxCurrentTCB);

                /* Disinherit the priority, remembering the previous
                     * priority to facilitate determining the subject task's
                     * state. */
                traceTASK_PRIORITY_DISINHERIT(pxTCB, uxPriorityToUse);
                //保存旧优先级
                uxPriorityUsedOnEntry = pxTCB->uxPriority;
                //设置新的优先级
                pxTCB->uxPriority = uxPriorityToUse;    

                /* Only reset the event list item value if the value is not
                     * being used for anything else. */
                //设置事件节点值
                if ((listGET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem)) & taskEVENT_LIST_ITEM_VALUE_IN_USE) == 0UL)
                {
                    listSET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)uxPriorityToUse); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                /* If the running task is not the task that holds the mutex
                     * then the task that holds the mutex could be in either the
                     * Ready, Blocked or Suspended states.  Only remove the task
                     * from its current state list if it is in the Ready state as
                     * the task's priority is going to change and there is one
                     * Ready list per priority. */
                //若锁的拥有者处于就绪链表，由于改变了优先级，所以需要修改其优先级链表
                if (listIS_CONTAINED_WITHIN(&(pxReadyTasksLists[uxPriorityUsedOnEntry]), &(pxTCB->xStateListItem)) != pdFALSE)
                {
                    if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0)
                    {
                        /* It is known that the task is in its ready list so
                             * there is no need to check again and the port level
                             * reset macro can be called directly. */
                        portRESET_READY_PRIORITY(pxTCB->uxPriority, uxTopReadyPriority);
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                    //插入新的就绪链表
                    prvAddTaskToReadyList(pxTCB);
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}


/*-----------------------------------------------------------*/

#if (portCRITICAL_NESTING_IN_TCB == 1)

void vTaskEnterCritical(void)
{
    portDISABLE_INTERRUPTS();

    if (xSchedulerRunning != pdFALSE)
    {
        (pxCurrentTCB->uxCriticalNesting)++;

        /* This is not the interrupt safe version of the enter critical
             * function so  assert() if it is being called from an interrupt
             * context.  Only API functions that end in "FromISR" can be used in an
             * interrupt.  Only assert if the critical nesting count is 1 to
             * protect against recursive calls if the assert function also uses a
             * critical section. */
        if (pxCurrentTCB->uxCriticalNesting == 1)
        {
            portASSERT_IF_IN_ISR();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

#endif /* portCRITICAL_NESTING_IN_TCB */
/*-----------------------------------------------------------*/

#if (portCRITICAL_NESTING_IN_TCB == 1)

void vTaskExitCritical(void)
{
    if (xSchedulerRunning != pdFALSE)
    {
        if (pxCurrentTCB->uxCriticalNesting > 0U)
        {
            (pxCurrentTCB->uxCriticalNesting)--;

            if (pxCurrentTCB->uxCriticalNesting == 0U)
            {
                portENABLE_INTERRUPTS();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

#endif /* portCRITICAL_NESTING_IN_TCB */
/*-----------------------------------------------------------*/

#if ((configUSE_TRACE_FACILITY == 1) && (configUSE_STATS_FORMATTING_FUNCTIONS > 0))

static char *prvWriteNameToBuffer(char *pcBuffer,
                                  const char *pcTaskName)
{
    size_t x;

    /* Start by copying the entire string. */
    strcpy(pcBuffer, pcTaskName);

    /* Pad the end of the string with spaces to ensure columns line up when
         * printed out. */
    for (x = strlen(pcBuffer); x < (size_t)(configMAX_TASK_NAME_LEN - 1); x++)
    {
        pcBuffer[x] = ' ';
    }

    /* Terminate. */
    pcBuffer[x] = (char)0x00;

    /* Return the new end of string. */
    return &(pcBuffer[x]);
}

#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
/*-----------------------------------------------------------*/

#if ((configUSE_TRACE_FACILITY == 1) && (configUSE_STATS_FORMATTING_FUNCTIONS > 0) && (configSUPPORT_DYNAMIC_ALLOCATION == 1))

void vTaskList(char *pcWriteBuffer)
{
    TaskStatus_t *pxTaskStatusArray;
    UBaseType_t uxArraySize, x;
    char cStatus;

    /*
         * PLEASE NOTE:
         *
         * This function is provided for convenience only, and is used by many
         * of the demo applications.  Do not consider it to be part of the
         * scheduler.
         *
         * vTaskList() calls uxTaskGetSystemState(), then formats part of the
         * uxTaskGetSystemState() output into a human readable table that
         * displays task names, states and stack usage.
         *
         * vTaskList() has a dependency on the sprintf() C library function that
         * might bloat the code size, use a lot of stack, and provide different
         * results on different platforms.  An alternative, tiny, third party,
         * and limited functionality implementation of sprintf() is provided in
         * many of the FreeRTOS/Demo sub-directories in a file called
         * printf-stdarg.c (note printf-stdarg.c does not provide a full
         * snprintf() implementation!).
         *
         * It is recommended that production systems call uxTaskGetSystemState()
         * directly to get access to raw stats data, rather than indirectly
         * through a call to vTaskList().
         */

    /* Make sure the write buffer does not contain a string. */
    *pcWriteBuffer = (char)0x00;

    /* Take a snapshot of the number of tasks in case it changes while this
         * function is executing. */
    uxArraySize = uxCurrentNumberOfTasks;

    /* Allocate an array index for each task.  NOTE!  if
         * configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will
         * equate to NULL. */
    pxTaskStatusArray = pvPortMalloc(uxCurrentNumberOfTasks * sizeof(TaskStatus_t)); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation allocates a struct that has the alignment requirements of a pointer. */

    if (pxTaskStatusArray != NULL)
    {
        /* Generate the (binary) data. */
        uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, NULL);

        /* Create a human readable table from the binary data. */
        for (x = 0; x < uxArraySize; x++)
        {
            switch (pxTaskStatusArray[x].eCurrentState)
            {
            case eRunning:
                cStatus = tskRUNNING_CHAR;
                break;

            case eReady:
                cStatus = tskREADY_CHAR;
                break;

            case eBlocked:
                cStatus = tskBLOCKED_CHAR;
                break;

            case eSuspended:
                cStatus = tskSUSPENDED_CHAR;
                break;

            case eDeleted:
                cStatus = tskDELETED_CHAR;
                break;

            case eInvalid: /* Fall through. */
            default:       /* Should not get here, but it is included
                                    * to prevent static checking errors. */
                cStatus = (char)0x00;
                break;
            }

            /* Write the task name to the string, padding with spaces so it
                 * can be printed in tabular form more easily. */
            pcWriteBuffer = prvWriteNameToBuffer(pcWriteBuffer, pxTaskStatusArray[x].pcTaskName);

            /* Write the rest of the string. */
            sprintf(pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, (unsigned int)pxTaskStatusArray[x].uxCurrentPriority, (unsigned int)pxTaskStatusArray[x].usStackHighWaterMark, (unsigned int)pxTaskStatusArray[x].xTaskNumber); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
            pcWriteBuffer += strlen(pcWriteBuffer);                                                                                                                                                                                 /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */
        }

        /* Free the array again.  NOTE!  If configSUPPORT_DYNAMIC_ALLOCATION
             * is 0 then vPortFree() will be #defined to nothing. */
        vPortFree(pxTaskStatusArray);
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */
/*----------------------------------------------------------*/

#if ((configGENERATE_RUN_TIME_STATS == 1) && (configUSE_STATS_FORMATTING_FUNCTIONS > 0) && (configSUPPORT_DYNAMIC_ALLOCATION == 1))

void vTaskGetRunTimeStats(char *pcWriteBuffer)
{
    TaskStatus_t *pxTaskStatusArray;
    UBaseType_t uxArraySize, x;
    uint32_t ulTotalTime, ulStatsAsPercentage;

#if (configUSE_TRACE_FACILITY != 1)
    {
#error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
    }
#endif

    /*
         * PLEASE NOTE:
         *
         * This function is provided for convenience only, and is used by many
         * of the demo applications.  Do not consider it to be part of the
         * scheduler.
         *
         * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part
         * of the uxTaskGetSystemState() output into a human readable table that
         * displays the amount of time each task has spent in the Running state
         * in both absolute and percentage terms.
         *
         * vTaskGetRunTimeStats() has a dependency on the sprintf() C library
         * function that might bloat the code size, use a lot of stack, and
         * provide different results on different platforms.  An alternative,
         * tiny, third party, and limited functionality implementation of
         * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in
         * a file called printf-stdarg.c (note printf-stdarg.c does not provide
         * a full snprintf() implementation!).
         *
         * It is recommended that production systems call uxTaskGetSystemState()
         * directly to get access to raw stats data, rather than indirectly
         * through a call to vTaskGetRunTimeStats().
         */

    /* Make sure the write buffer does not contain a string. */
    *pcWriteBuffer = (char)0x00;

    /* Take a snapshot of the number of tasks in case it changes while this
         * function is executing. */
    uxArraySize = uxCurrentNumberOfTasks;

    /* Allocate an array index for each task.  NOTE!  If
         * configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will
         * equate to NULL. */
    pxTaskStatusArray = pvPortMalloc(uxCurrentNumberOfTasks * sizeof(TaskStatus_t)); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation allocates a struct that has the alignment requirements of a pointer. */

    if (pxTaskStatusArray != NULL)
    {
        /* Generate the (binary) data. */
        uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalTime);

        /* For percentage calculations. */
        ulTotalTime /= 100UL;

        /* Avoid divide by zero errors. */
        if (ulTotalTime > 0UL)
        {
            /* Create a human readable table from the binary data. */
            for (x = 0; x < uxArraySize; x++)
            {
                /* What percentage of the total run time has the task used?
                     * This will always be rounded down to the nearest integer.
                     * ulTotalRunTimeDiv100 has already been divided by 100. */
                ulStatsAsPercentage = pxTaskStatusArray[x].ulRunTimeCounter / ulTotalTime;

                /* Write the task name to the string, padding with
                     * spaces so it can be printed in tabular form more
                     * easily. */
                pcWriteBuffer = prvWriteNameToBuffer(pcWriteBuffer, pxTaskStatusArray[x].pcTaskName);

                if (ulStatsAsPercentage > 0UL)
                {
#ifdef portLU_PRINTF_SPECIFIER_REQUIRED
                    {
                        sprintf(pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[x].ulRunTimeCounter, ulStatsAsPercentage);
                    }
#else
                    {
                        /* sizeof( int ) == sizeof( long ) so a smaller
                                 * printf() library can be used. */
                        sprintf(pcWriteBuffer, "\t%u\t\t%u%%\r\n", (unsigned int)pxTaskStatusArray[x].ulRunTimeCounter, (unsigned int)ulStatsAsPercentage); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
                    }
#endif
                }
                else
                {
/* If the percentage is zero here then the task has
                         * consumed less than 1% of the total run time. */
#ifdef portLU_PRINTF_SPECIFIER_REQUIRED
                    {
                        sprintf(pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[x].ulRunTimeCounter);
                    }
#else
                    {
                        /* sizeof( int ) == sizeof( long ) so a smaller
                                 * printf() library can be used. */
                        sprintf(pcWriteBuffer, "\t%u\t\t<1%%\r\n", (unsigned int)pxTaskStatusArray[x].ulRunTimeCounter); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
                    }
#endif
                }

                pcWriteBuffer += strlen(pcWriteBuffer); /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* Free the array again.  NOTE!  If configSUPPORT_DYNAMIC_ALLOCATION
             * is 0 then vPortFree() will be #defined to nothing. */
        vPortFree(pxTaskStatusArray);
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */
/*-----------------------------------------------------------*/

TickType_t uxTaskResetEventItemValue(void)
{
    TickType_t uxReturn;

    uxReturn = listGET_LIST_ITEM_VALUE(&(pxCurrentTCB->xEventListItem));

    /* Reset the event list item to its normal value - so it can be used with
     * queues and semaphores. */
    //重置为优先级排序
    listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xEventListItem), ((TickType_t)configMAX_PRIORITIES - (TickType_t)pxCurrentTCB->uxPriority)); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */

    return uxReturn;
}
/*-----------------------------------------------------------*/



TaskHandle_t pvTaskIncrementMutexHeldCount(void)
{
    /* If xSemaphoreCreateMutex() is called before any tasks have been created
         * then pxCurrentTCB will be NULL. */
    if (pxCurrentTCB != NULL)
    {
        (pxCurrentTCB->uxMutexesHeld)++;
    }

    return pxCurrentTCB;
}


/*-----------------------------------------------------------*/

#if (configUSE_TASK_NOTIFICATIONS == 1)

uint32_t ulTaskGenericNotifyTake(UBaseType_t uxIndexToWait,
                                 BaseType_t xClearCountOnExit,
                                 TickType_t xTicksToWait)
{
    uint32_t ulReturn;

    configASSERT(uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES);

    taskENTER_CRITICAL();
    {
        /* Only block if the notification count is not already non-zero. */
        if (pxCurrentTCB->ulNotifiedValue[uxIndexToWait] == 0UL)
        {
            /* Mark this task as waiting for a notification. */
            pxCurrentTCB->ucNotifyState[uxIndexToWait] = taskWAITING_NOTIFICATION;

            if (xTicksToWait > (TickType_t)0)
            {
                prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE);
                traceTASK_NOTIFY_TAKE_BLOCK(uxIndexToWait);

                /* All ports are written to allow a yield in a critical
                     * section (some will yield immediately, others wait until the
                     * critical section exits) - but it is not something that
                     * application code should ever do. */
                portYIELD_WITHIN_API();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    taskEXIT_CRITICAL();

    taskENTER_CRITICAL();
    {
        traceTASK_NOTIFY_TAKE(uxIndexToWait);
        ulReturn = pxCurrentTCB->ulNotifiedValue[uxIndexToWait];

        if (ulReturn != 0UL)
        {
            if (xClearCountOnExit != pdFALSE)
            {
                pxCurrentTCB->ulNotifiedValue[uxIndexToWait] = 0UL;
            }
            else
            {
                pxCurrentTCB->ulNotifiedValue[uxIndexToWait] = ulReturn - (uint32_t)1;
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        pxCurrentTCB->ucNotifyState[uxIndexToWait] = taskNOT_WAITING_NOTIFICATION;
    }
    taskEXIT_CRITICAL();

    return ulReturn;
}

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

#if (configUSE_TASK_NOTIFICATIONS == 1)

BaseType_t xTaskGenericNotifyWait(UBaseType_t uxIndexToWait,
                                  uint32_t ulBitsToClearOnEntry,
                                  uint32_t ulBitsToClearOnExit,
                                  uint32_t *pulNotificationValue,
                                  TickType_t xTicksToWait)
{
    BaseType_t xReturn;

    configASSERT(uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES);

    taskENTER_CRITICAL();
    {
        /* Only block if a notification is not already pending. */
        if (pxCurrentTCB->ucNotifyState[uxIndexToWait] != taskNOTIFICATION_RECEIVED)
        {
            /* Clear bits in the task's notification value as bits may get
                 * set  by the notifying task or interrupt.  This can be used to
                 * clear the value to zero. */
            pxCurrentTCB->ulNotifiedValue[uxIndexToWait] &= ~ulBitsToClearOnEntry;

            /* Mark this task as waiting for a notification. */
            pxCurrentTCB->ucNotifyState[uxIndexToWait] = taskWAITING_NOTIFICATION;

            if (xTicksToWait > (TickType_t)0)
            {
                prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE);
                traceTASK_NOTIFY_WAIT_BLOCK(uxIndexToWait);

                /* All ports are written to allow a yield in a critical
                     * section (some will yield immediately, others wait until the
                     * critical section exits) - but it is not something that
                     * application code should ever do. */
                portYIELD_WITHIN_API();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    taskEXIT_CRITICAL();

    taskENTER_CRITICAL();
    {
        traceTASK_NOTIFY_WAIT(uxIndexToWait);

        if (pulNotificationValue != NULL)
        {
            /* Output the current notification value, which may or may not
                 * have changed. */
            *pulNotificationValue = pxCurrentTCB->ulNotifiedValue[uxIndexToWait];
        }

        /* If ucNotifyValue is set then either the task never entered the
             * blocked state (because a notification was already pending) or the
             * task unblocked because of a notification.  Otherwise the task
             * unblocked because of a timeout. */
        if (pxCurrentTCB->ucNotifyState[uxIndexToWait] != taskNOTIFICATION_RECEIVED)
        {
            /* A notification was not received. */
            xReturn = pdFALSE;
        }
        else
        {
            /* A notification was already pending or a notification was
                 * received while the task was waiting. */
            pxCurrentTCB->ulNotifiedValue[uxIndexToWait] &= ~ulBitsToClearOnExit;
            xReturn = pdTRUE;
        }

        pxCurrentTCB->ucNotifyState[uxIndexToWait] = taskNOT_WAITING_NOTIFICATION;
    }
    taskEXIT_CRITICAL();

    return xReturn;
}

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

#if (configUSE_TASK_NOTIFICATIONS == 1)

BaseType_t xTaskGenericNotify(TaskHandle_t xTaskToNotify,
                              UBaseType_t uxIndexToNotify,
                              uint32_t ulValue,
                              eNotifyAction eAction,
                              uint32_t *pulPreviousNotificationValue)
{
    TCB_t *pxTCB;
    BaseType_t xReturn = pdPASS;
    uint8_t ucOriginalNotifyState;

    configASSERT(uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES);
    configASSERT(xTaskToNotify);
    pxTCB = xTaskToNotify;

    taskENTER_CRITICAL();
    {
        if (pulPreviousNotificationValue != NULL)
        {
            *pulPreviousNotificationValue = pxTCB->ulNotifiedValue[uxIndexToNotify];
        }

        ucOriginalNotifyState = pxTCB->ucNotifyState[uxIndexToNotify];

        pxTCB->ucNotifyState[uxIndexToNotify] = taskNOTIFICATION_RECEIVED;

        switch (eAction)
        {
        case eSetBits:
            pxTCB->ulNotifiedValue[uxIndexToNotify] |= ulValue;
            break;

        case eIncrement:
            (pxTCB->ulNotifiedValue[uxIndexToNotify])++;
            break;

        case eSetValueWithOverwrite:
            pxTCB->ulNotifiedValue[uxIndexToNotify] = ulValue;
            break;

        case eSetValueWithoutOverwrite:

            if (ucOriginalNotifyState != taskNOTIFICATION_RECEIVED)
            {
                pxTCB->ulNotifiedValue[uxIndexToNotify] = ulValue;
            }
            else
            {
                /* The value could not be written to the task. */
                xReturn = pdFAIL;
            }

            break;

        case eNoAction:

            /* The task is being notified without its notify value being
                     * updated. */
            break;

        default:

            /* Should not get here if all enums are handled.
                     * Artificially force an assert by testing a value the
                     * compiler can't assume is const. */
            configASSERT(xTickCount == (TickType_t)0);

            break;
        }

        traceTASK_NOTIFY(uxIndexToNotify);

        /* If the task is in the blocked state specifically to wait for a
             * notification then unblock it now. */
        if (ucOriginalNotifyState == taskWAITING_NOTIFICATION)
        {
            (void)uxListRemove(&(pxTCB->xStateListItem));
            prvAddTaskToReadyList(pxTCB);

            /* The task should not have been on an event list. */
            configASSERT(listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL);

#if (configUSE_TICKLESS_IDLE != 0)
            {
                /* If a task is blocked waiting for a notification then
                         * xNextTaskUnblockTime might be set to the blocked task's time
                         * out time.  If the task is unblocked for a reason other than
                         * a timeout xNextTaskUnblockTime is normally left unchanged,
                         * because it will automatically get reset to a new value when
                         * the tick count equals xNextTaskUnblockTime.  However if
                         * tickless idling is used it might be more important to enter
                         * sleep mode at the earliest possible time - so reset
                         * xNextTaskUnblockTime here to ensure it is updated at the
                         * earliest possible time. */
                prvResetNextTaskUnblockTime();
            }
#endif

            if (pxTCB->uxPriority > pxCurrentTCB->uxPriority)
            {
                /* The notified task has a priority above the currently
                     * executing task so a yield is required. */
                taskYIELD_IF_USING_PREEMPTION();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    taskEXIT_CRITICAL();

    return xReturn;
}

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

#if (configUSE_TASK_NOTIFICATIONS == 1)

BaseType_t xTaskGenericNotifyFromISR(TaskHandle_t xTaskToNotify,
                                     UBaseType_t uxIndexToNotify,
                                     uint32_t ulValue,
                                     eNotifyAction eAction,
                                     uint32_t *pulPreviousNotificationValue,
                                     BaseType_t *pxHigherPriorityTaskWoken)
{
    TCB_t *pxTCB;
    uint8_t ucOriginalNotifyState;
    BaseType_t xReturn = pdPASS;
    UBaseType_t uxSavedInterruptStatus;

    configASSERT(xTaskToNotify);
    configASSERT(uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES);

    /* RTOS ports that support interrupt nesting have the concept of a
         * maximum  system call (or maximum API call) interrupt priority.
         * Interrupts that are  above the maximum system call priority are keep
         * permanently enabled, even when the RTOS kernel is in a critical section,
         * but cannot make any calls to FreeRTOS API functions.  If configASSERT()
         * is defined in FreeRTOSConfig.h then
         * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
         * failure if a FreeRTOS API function is called from an interrupt that has
         * been assigned a priority above the configured maximum system call
         * priority.  Only FreeRTOS functions that end in FromISR can be called
         * from interrupts  that have been assigned a priority at or (logically)
         * below the maximum system call interrupt priority.  FreeRTOS maintains a
         * separate interrupt safe API to ensure interrupt entry is as fast and as
         * simple as possible.  More information (albeit Cortex-M specific) is
         * provided on the following link:
         * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
    portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

    pxTCB = xTaskToNotify;

    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        if (pulPreviousNotificationValue != NULL)
        {
            *pulPreviousNotificationValue = pxTCB->ulNotifiedValue[uxIndexToNotify];
        }

        ucOriginalNotifyState = pxTCB->ucNotifyState[uxIndexToNotify];
        pxTCB->ucNotifyState[uxIndexToNotify] = taskNOTIFICATION_RECEIVED;

        switch (eAction)
        {
        case eSetBits:
            pxTCB->ulNotifiedValue[uxIndexToNotify] |= ulValue;
            break;

        case eIncrement:
            (pxTCB->ulNotifiedValue[uxIndexToNotify])++;
            break;

        case eSetValueWithOverwrite:
            pxTCB->ulNotifiedValue[uxIndexToNotify] = ulValue;
            break;

        case eSetValueWithoutOverwrite:

            if (ucOriginalNotifyState != taskNOTIFICATION_RECEIVED)
            {
                pxTCB->ulNotifiedValue[uxIndexToNotify] = ulValue;
            }
            else
            {
                /* The value could not be written to the task. */
                xReturn = pdFAIL;
            }

            break;

        case eNoAction:

            /* The task is being notified without its notify value being
                     * updated. */
            break;

        default:

            /* Should not get here if all enums are handled.
                     * Artificially force an assert by testing a value the
                     * compiler can't assume is const. */
            configASSERT(xTickCount == (TickType_t)0);
            break;
        }

        traceTASK_NOTIFY_FROM_ISR(uxIndexToNotify);

        /* If the task is in the blocked state specifically to wait for a
             * notification then unblock it now. */
        if (ucOriginalNotifyState == taskWAITING_NOTIFICATION)
        {
            /* The task should not have been on an event list. */
            configASSERT(listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL);

            if (uxSchedulerSuspended == (UBaseType_t)pdFALSE)
            {
                (void)uxListRemove(&(pxTCB->xStateListItem));
                prvAddTaskToReadyList(pxTCB);
            }
            else
            {
                /* The delayed and ready lists cannot be accessed, so hold
                     * this task pending until the scheduler is resumed. */
                vListInsertEnd(&(xPendingReadyList), &(pxTCB->xEventListItem));
            }

            if (pxTCB->uxPriority > pxCurrentTCB->uxPriority)
            {
                /* The notified task has a priority above the currently
                     * executing task so a yield is required. */
                if (pxHigherPriorityTaskWoken != NULL)
                {
                    *pxHigherPriorityTaskWoken = pdTRUE;
                }

                /* Mark that a yield is pending in case the user is not
                     * using the "xHigherPriorityTaskWoken" parameter to an ISR
                     * safe FreeRTOS function. */
                xYieldPending = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);

    return xReturn;
}

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

#if (configUSE_TASK_NOTIFICATIONS == 1)

void vTaskGenericNotifyGiveFromISR(TaskHandle_t xTaskToNotify,
                                   UBaseType_t uxIndexToNotify,
                                   BaseType_t *pxHigherPriorityTaskWoken)
{
    TCB_t *pxTCB;
    uint8_t ucOriginalNotifyState;
    UBaseType_t uxSavedInterruptStatus;

    configASSERT(xTaskToNotify);
    configASSERT(uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES);

    /* RTOS ports that support interrupt nesting have the concept of a
         * maximum  system call (or maximum API call) interrupt priority.
         * Interrupts that are  above the maximum system call priority are keep
         * permanently enabled, even when the RTOS kernel is in a critical section,
         * but cannot make any calls to FreeRTOS API functions.  If configASSERT()
         * is defined in FreeRTOSConfig.h then
         * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
         * failure if a FreeRTOS API function is called from an interrupt that has
         * been assigned a priority above the configured maximum system call
         * priority.  Only FreeRTOS functions that end in FromISR can be called
         * from interrupts  that have been assigned a priority at or (logically)
         * below the maximum system call interrupt priority.  FreeRTOS maintains a
         * separate interrupt safe API to ensure interrupt entry is as fast and as
         * simple as possible.  More information (albeit Cortex-M specific) is
         * provided on the following link:
         * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
    portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

    pxTCB = xTaskToNotify;

    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        ucOriginalNotifyState = pxTCB->ucNotifyState[uxIndexToNotify];
        pxTCB->ucNotifyState[uxIndexToNotify] = taskNOTIFICATION_RECEIVED;

        /* 'Giving' is equivalent to incrementing a count in a counting
             * semaphore. */
        (pxTCB->ulNotifiedValue[uxIndexToNotify])++;

        traceTASK_NOTIFY_GIVE_FROM_ISR(uxIndexToNotify);

        /* If the task is in the blocked state specifically to wait for a
             * notification then unblock it now. */
        if (ucOriginalNotifyState == taskWAITING_NOTIFICATION)
        {
            /* The task should not have been on an event list. */
            configASSERT(listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL);

            if (uxSchedulerSuspended == (UBaseType_t)pdFALSE)
            {
                (void)uxListRemove(&(pxTCB->xStateListItem));
                prvAddTaskToReadyList(pxTCB);
            }
            else
            {
                /* The delayed and ready lists cannot be accessed, so hold
                     * this task pending until the scheduler is resumed. */
                vListInsertEnd(&(xPendingReadyList), &(pxTCB->xEventListItem));
            }

            if (pxTCB->uxPriority > pxCurrentTCB->uxPriority)
            {
                /* The notified task has a priority above the currently
                     * executing task so a yield is required. */
                if (pxHigherPriorityTaskWoken != NULL)
                {
                    *pxHigherPriorityTaskWoken = pdTRUE;
                }

                /* Mark that a yield is pending in case the user is not
                     * using the "xHigherPriorityTaskWoken" parameter in an ISR
                     * safe FreeRTOS function. */
                xYieldPending = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
}

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

#if (configUSE_TASK_NOTIFICATIONS == 1)

BaseType_t xTaskGenericNotifyStateClear(TaskHandle_t xTask,
                                        UBaseType_t uxIndexToClear)
{
    TCB_t *pxTCB;
    BaseType_t xReturn;

    configASSERT(uxIndexToClear < configTASK_NOTIFICATION_ARRAY_ENTRIES);

    /* If null is passed in here then it is the calling task that is having
         * its notification state cleared. */
    pxTCB = prvGetTCBFromHandle(xTask);

    taskENTER_CRITICAL();
    {
        if (pxTCB->ucNotifyState[uxIndexToClear] == taskNOTIFICATION_RECEIVED)
        {
            pxTCB->ucNotifyState[uxIndexToClear] = taskNOT_WAITING_NOTIFICATION;
            xReturn = pdPASS;
        }
        else
        {
            xReturn = pdFAIL;
        }
    }
    taskEXIT_CRITICAL();

    return xReturn;
}

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

#if (configUSE_TASK_NOTIFICATIONS == 1)

uint32_t ulTaskGenericNotifyValueClear(TaskHandle_t xTask,
                                       UBaseType_t uxIndexToClear,
                                       uint32_t ulBitsToClear)
{
    TCB_t *pxTCB;
    uint32_t ulReturn;

    /* If null is passed in here then it is the calling task that is having
         * its notification state cleared. */
    pxTCB = prvGetTCBFromHandle(xTask);

    taskENTER_CRITICAL();
    {
        /* Return the notification as it was before the bits were cleared,
             * then clear the bit mask. */
        ulReturn = pxTCB->ulNotifiedValue[uxIndexToClear];
        pxTCB->ulNotifiedValue[uxIndexToClear] &= ~ulBitsToClear;
    }
    taskEXIT_CRITICAL();

    return ulReturn;
}

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

#if ((configGENERATE_RUN_TIME_STATS == 1) && (INCLUDE_xTaskGetIdleTaskHandle == 1))

uint32_t ulTaskGetIdleRunTimeCounter(void)
{
    return xIdleTaskHandle->ulRunTimeCounter;
}

#endif
/*-----------------------------------------------------------*/

static void prvAddCurrentTaskToDelayedList(TickType_t xTicksToWait,
                                           const BaseType_t xCanBlockIndefinitely)
{
    TickType_t xTimeToWake;
    const TickType_t xConstTickCount = xTickCount; //保存当前时钟计数值为常量

#if (INCLUDE_xTaskAbortDelay == 1)
    {
        //进入延时链表、设置标记
        pxCurrentTCB->ucDelayAborted = pdFALSE;
    }
#endif

    //首先将当前任务移出就绪链表 若返回为0说明该优先级链表为空 需要重置最高优先级
    if (uxListRemove(&(pxCurrentTCB->xStateListItem)) == (UBaseType_t)0)
    {

        portRESET_READY_PRIORITY(pxCurrentTCB->uxPriority, uxTopReadyPriority);
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }


    {
        //若延时时间最大且无限期等待，则直接加入挂起链表 任务调度器不对其管理
        if ((xTicksToWait == portMAX_DELAY) && (xCanBlockIndefinitely != pdFALSE))
        {

            vListInsertEnd(&xSuspendedTaskList, &(pxCurrentTCB->xStateListItem));
        }
        else   //插入延时链表
        {
            //计算任务下次由时钟中断唤醒的时间戳 注意时钟溢出（当前时间+需要等待的时间=下次醒来的时间点）
            xTimeToWake = xConstTickCount + xTicksToWait;

            //将时间戳设置为任务的状态节点值
            listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xStateListItem), xTimeToWake);

            if (xTimeToWake < xConstTickCount)
            {
                //延时时间溢出、任务插入延时溢出链表
                vListInsert(pxOverflowDelayedTaskList, &(pxCurrentTCB->xStateListItem));
            }
            else
            {
                //未溢出，插入当前延时链表
                vListInsert(pxDelayedTaskList, &(pxCurrentTCB->xStateListItem));

                //更新xNextTaskUnblockTime
                if (xTimeToWake < xNextTaskUnblockTime)
                {
                    xNextTaskUnblockTime = xTimeToWake;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
        }
    }

    //不支持任务挂起
    {

        xTimeToWake = xConstTickCount + xTicksToWait;

        listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xStateListItem), xTimeToWake);

        if (xTimeToWake < xConstTickCount)
        {

            vListInsert(pxOverflowDelayedTaskList, &(pxCurrentTCB->xStateListItem));
        }
        else
        {
            vListInsert(pxDelayedTaskList, &(pxCurrentTCB->xStateListItem));

            if (xTimeToWake < xNextTaskUnblockTime)
            {
                xNextTaskUnblockTime = xTimeToWake;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }

        /* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */
        (void)xCanBlockIndefinitely;
    }

}

/* Code below here allows additional code to be inserted into this source file,
 * especially where access to file scope functions and data is needed (for example
 * when performing module tests). */

#ifdef FREERTOS_MODULE_TEST
#include "tasks_test_access_functions.h"
#endif

#if (configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1)

#include "freertos_tasks_c_additions.h"

#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
static void freertos_tasks_c_additions_init(void)
{
    FREERTOS_TASKS_C_ADDITIONS_INIT();
}
#endif

#endif /* if ( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 ) */
